From fb008378dbd864cdaa636a16374a52fd97bb3fed Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Mon, 22 May 2017 17:03:43 +0300 Subject: [PATCH 001/265] Don't use mg_str And just use ad-hoc struct instead. This is because we don't really use anything from mg_str other than the struct definition, so there's no need to amalgam mg_str.h into mjs.c, add it to publishing, etc. PUBLISHED_FROM=9ded3c3603c9ba5893387c087afeaede9c123837 --- mjs.c | 76 +++------------------------------------------ mjs/src/mjs_bcode.c | 2 +- mjs/src/mjs_core.h | 7 +++-- 3 files changed, 10 insertions(+), 75 deletions(-) diff --git a/mjs.c b/mjs.c index a882d87..ec02299 100644 --- a/mjs.c +++ b/mjs.c @@ -2251,73 +2251,6 @@ MJS_PRIVATE void mjs_array_splice(struct mjs *mjs); #endif /* MJS_ARRAY_H_ */ #ifdef MJS_MODULE_LINES -#line 1 "common/mg_str.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_MG_STR_H_ -#define CS_COMMON_MG_STR_H_ - -#include - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Describes chunk of memory */ -struct mg_str { - const char *p; /* Memory chunk pointer */ - size_t len; /* Memory chunk length */ -}; - -/* - * Helper functions for creating mg_str struct from plain C string. - * `NULL` is allowed and becomes `{NULL, 0}`. - */ -struct mg_str mg_mk_str(const char *s); -struct mg_str mg_mk_str_n(const char *s, size_t len); - -/* Macro for initializing mg_str. */ -#define MG_MK_STR(str_literal) \ - { str_literal, sizeof(str_literal) - 1 } -#define MG_NULL_STR \ - { NULL, 0 } - -/* - * Cross-platform version of `strcmp()` where where first string is - * specified by `struct mg_str`. - */ -int mg_vcmp(const struct mg_str *str2, const char *str1); - -/* - * Cross-platform version of `strncasecmp()` where first string is - * specified by `struct mg_str`. - */ -int mg_vcasecmp(const struct mg_str *str2, const char *str1); - -/* Creates a copy of s (heap-allocated). */ -struct mg_str mg_strdup(const struct mg_str s); - -/* - * Creates a copy of s (heap-allocated). - * Resulting string is NUL-terminated (but NUL is not included in len). - */ -struct mg_str mg_strdup_nul(const struct mg_str s); - -int mg_strcmp(const struct mg_str str1, const struct mg_str str2); -int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MG_STR_H_ */ -#ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_ffi_public.h" #endif /* @@ -2621,8 +2554,6 @@ MJS_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *p); #ifndef MJS_CORE_H #define MJS_CORE_H -/* Amalgamated: #include "common/mg_str.h" */ - /* Amalgamated: #include "mjs/src/mjs_ffi.h" */ /* Amalgamated: #include "mjs/src/mjs_gc.h" */ /* Amalgamated: #include "mjs/src/mjs_internal.h" */ @@ -2707,7 +2638,10 @@ struct mjs_bcode_part { size_t start_idx; /* Actual bcode data */ - struct mg_str data; + struct { + const char *p; /* Memory chunk pointer */ + size_t len; /* Memory chunk length */ + } data; /* * Result of evaluation (not parsing: if there is an error during parsing, @@ -6424,7 +6358,7 @@ MJS_PRIVATE void mjs_bcode_commit(struct mjs *mjs) { /* Make sure the bcode doesn't occupy any extra space */ mbuf_trim(&mjs->bcode_gen); - /* Transfer the ownership of the bcode data to the new mg_str */ + /* Transfer the ownership of the bcode data */ bp.data.p = mjs->bcode_gen.buf; bp.data.len = mjs->bcode_gen.len; mbuf_init(&mjs->bcode_gen, 0); diff --git a/mjs/src/mjs_bcode.c b/mjs/src/mjs_bcode.c index a2441fd..fa733dc 100644 --- a/mjs/src/mjs_bcode.c +++ b/mjs/src/mjs_bcode.c @@ -132,7 +132,7 @@ MJS_PRIVATE void mjs_bcode_commit(struct mjs *mjs) { /* Make sure the bcode doesn't occupy any extra space */ mbuf_trim(&mjs->bcode_gen); - /* Transfer the ownership of the bcode data to the new mg_str */ + /* Transfer the ownership of the bcode data */ bp.data.p = mjs->bcode_gen.buf; bp.data.len = mjs->bcode_gen.len; mbuf_init(&mjs->bcode_gen, 0); diff --git a/mjs/src/mjs_core.h b/mjs/src/mjs_core.h index 9067a74..2d07813 100644 --- a/mjs/src/mjs_core.h +++ b/mjs/src/mjs_core.h @@ -6,8 +6,6 @@ #ifndef MJS_CORE_H #define MJS_CORE_H -#include "common/mg_str.h" - #include "mjs/src/mjs_ffi.h" #include "mjs/src/mjs_gc.h" #include "mjs/src/mjs_internal.h" @@ -92,7 +90,10 @@ struct mjs_bcode_part { size_t start_idx; /* Actual bcode data */ - struct mg_str data; + struct { + const char *p; /* Memory chunk pointer */ + size_t len; /* Memory chunk length */ + } data; /* * Result of evaluation (not parsing: if there is an error during parsing, From b1dd9985190a0139ab1336005700a4b811651ce0 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Mon, 22 May 2017 22:50:38 +0300 Subject: [PATCH 002/265] Add common.mk to mjs publishing PUBLISHED_FROM=d1d97de97ec96ff9192de88bc8226d7e36e5334a --- common.mk | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 common.mk diff --git a/common.mk b/common.mk new file mode 100644 index 0000000..acdafec --- /dev/null +++ b/common.mk @@ -0,0 +1,37 @@ +GO_PACKAGES = $(shell go list cesanta.com/cloud/... | grep -v vendor) \ + cesanta.com/be/... \ + cesanta.com/clubby/... \ + cesanta.com/common/... \ + cesanta.com/fw/... \ + cesanta.com/mos/... \ + cesanta.com/ourci/... \ + cesanta.com/projects/breez/... + +FORMAT_FILES ?= '*.[ch]' +REPO_ABS_PATH := $(shell cd $(REPO_ROOT) && pwd) + +CLANG = clang +ifneq ("$(wildcard /usr/bin/clang-3.6)","") + CLANG:=/usr/bin/clang-3.6 +endif + +# installable with: `brew install llvm36 --with-clang` +ifneq ("$(wildcard /usr/local/bin/clang-format-3.6)","") + CLANG_FORMAT = /usr/local/bin/clang-format-3.6 +else ifneq ("$(wildcard /usr/bin/clang-format-3.6)","") + CLANG_FORMAT = /usr/bin/clang-format-3.6 +else + CLANG_FORMAT = docker run --rm \ + -v $(REPO_ABS_PATH):$(REPO_ABS_PATH) \ + $(DOCKER_USER_ARG) \ + docker.cesanta.com/bob \ + /usr/bin/clang-format-3.6 +endif + +format: + @echo "Formatting $$(basename $(CURDIR))" + @test -d "$(REPO_ROOT)" && true || { echo "Define REPO_ROOT Makefile variable, REPO_ROOT/common.mk wants it." ; false ; } + @git --git-dir $(REPO_ABS_PATH)/.git --work-tree $(REPO_ROOT) \ + ls-files --full-name $(FORMAT_FILES) | \ + xargs -IFILE echo $(REPO_ABS_PATH)/FILE | \ + xargs -t $(CLANG_FORMAT) -i From c8d53f1afc5b80db101c0343718d5677df795ce7 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Mon, 22 May 2017 21:56:13 +0100 Subject: [PATCH 003/265] Don't crash on division by zero For x % 0, NaN is fine. For division by zero, JS actually returns Infinity, but so far mjs also returns NaN. PUBLISHED_FROM=b863c4f56f42f5a14124d1d160f3e2b18ec5a9ea --- mjs.c | 15 +++++++++++++-- mjs/src/mjs_exec.c | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index ec02299..d683347 100644 --- a/mjs.c +++ b/mjs.c @@ -7154,8 +7154,19 @@ static double do_arith_op(double da, double db, int op) { case TOK_MINUS: return da - db; case TOK_PLUS: return da + db; case TOK_MUL: return da * db; - case TOK_DIV: return da / db; - case TOK_REM: return (int64_t) da % (int64_t) db; + case TOK_DIV: + if (db != 0) { + return da / db; + } else { + /* TODO(dfrank): add support for Infinity and return it here */ + return MJS_TAG_NAN; + } + case TOK_REM: + if (db != 0) { + return (int64_t) da % (int64_t) db; + } else { + return MJS_TAG_NAN; + } case TOK_AND: return (int64_t) da & (int64_t) db; case TOK_OR: return (int64_t) da | (int64_t) db; case TOK_XOR: return (int64_t) da ^ (int64_t) db; diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 0842e86..1610d06 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -86,8 +86,19 @@ static double do_arith_op(double da, double db, int op) { case TOK_MINUS: return da - db; case TOK_PLUS: return da + db; case TOK_MUL: return da * db; - case TOK_DIV: return da / db; - case TOK_REM: return (int64_t) da % (int64_t) db; + case TOK_DIV: + if (db != 0) { + return da / db; + } else { + /* TODO(dfrank): add support for Infinity and return it here */ + return MJS_TAG_NAN; + } + case TOK_REM: + if (db != 0) { + return (int64_t) da % (int64_t) db; + } else { + return MJS_TAG_NAN; + } case TOK_AND: return (int64_t) da & (int64_t) db; case TOK_OR: return (int64_t) da | (int64_t) db; case TOK_XOR: return (int64_t) da ^ (int64_t) db; From eb8717b9114d5326dd48132181f907f21803aba6 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 23 May 2017 00:45:14 +0300 Subject: [PATCH 004/265] Fix cs_varint and add tests for it The main problem was that the length of encoded varint was assumed to be not larger than `sizeof(uint64_t)`, but it's obviously not true, because varint-encoded `0xffffffffffffffff` takes 10 bytes. PUBLISHED_FROM=ccd372edaf4300b8ae0f3ce34a52676ff4f7a3f3 --- common/cs_varint.c | 18 ++++++++++++------ common/cs_varint.h | 6 +++--- common/test_util.h | 2 +- mjs.c | 24 +++++++++++++++--------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/common/cs_varint.c b/common/cs_varint.c index e19beea..16367b1 100644 --- a/common/cs_varint.c +++ b/common/cs_varint.c @@ -5,32 +5,38 @@ #include "common/cs_varint.h" +#include + /* * Strings in AST are encoded as tuples (length, string). * Length is variable-length: if high bit is set in a byte, next byte is used. * Small string length (less then 128 bytes) is encoded in 1 byte. */ -int64_t cs_varint_decode(const uint8_t *p, int *llen) { - int64_t i = 0, num = 0; +uint64_t cs_varint_decode(const uint8_t *p, int *llen) { + unsigned int i = 0; + unsigned int shift = 0; + uint64_t num = 0; do { /* * Each byte of varint contains 7 bits, in little endian order. * MSB is a continuation bit: it tells whether next byte is used. */ - num |= ((int64_t)(p[i] & 0x7f)) << (7 * i); + num |= ((uint64_t)(p[i] & 0x7f)) << shift; /* * First we increment i, then check whether it is within boundary and * whether decoded byte had continuation bit set. */ - } while ((unsigned int) ++i < sizeof(int64_t) && (p[i - 1] & 0x80)); + i++; + shift += 7; + } while (shift < sizeof(uint64_t) * 8 && (p[i - 1] & 0x80)); *llen = i; return num; } /* Return number of bytes to store length */ -int cs_varint_llen(int64_t num) { +int cs_varint_llen(uint64_t num) { int n = 0; do { @@ -40,7 +46,7 @@ int cs_varint_llen(int64_t num) { return n; } -int cs_varint_encode(int64_t num, uint8_t *p) { +int cs_varint_encode(uint64_t num, uint8_t *p) { int i, llen = cs_varint_llen(num); for (i = 0; i < llen; i++) { diff --git a/common/cs_varint.h b/common/cs_varint.h index ff98308..229f763 100644 --- a/common/cs_varint.h +++ b/common/cs_varint.h @@ -12,9 +12,9 @@ extern "C" { #endif /* __cplusplus */ -int cs_varint_encode(int64_t num, uint8_t *to); -int64_t cs_varint_decode(const uint8_t *from, int *llen); -int cs_varint_llen(int64_t num); +int cs_varint_encode(uint64_t num, uint8_t *to); +uint64_t cs_varint_decode(const uint8_t *from, int *llen); +int cs_varint_llen(uint64_t num); #if defined(__cplusplus) } diff --git a/common/test_util.h b/common/test_util.h index 477afc1..4cd0501 100644 --- a/common/test_util.h +++ b/common/test_util.h @@ -77,7 +77,7 @@ void _strfail(const char *a, const char *e, int len); #endif /* - * Numeric equality assertion. Compariosn is made in native types but for + * Numeric equality assertion. Comparison is made in native types but for * printing both are convetrted to double. */ #define ASSERT_EQ(actual, expected) \ diff --git a/mjs.c b/mjs.c index d683347..20f6169 100644 --- a/mjs.c +++ b/mjs.c @@ -1529,9 +1529,9 @@ char *cs_mmap_file(const char *path, size_t *size); extern "C" { #endif /* __cplusplus */ -int cs_varint_encode(int64_t num, uint8_t *to); -int64_t cs_varint_decode(const uint8_t *from, int *llen); -int cs_varint_llen(int64_t num); +int cs_varint_encode(uint64_t num, uint8_t *to); +uint64_t cs_varint_decode(const uint8_t *from, int *llen); +int cs_varint_llen(uint64_t num); #if defined(__cplusplus) } @@ -4197,32 +4197,38 @@ char *cs_mmap_file(const char *path, size_t *size) { /* Amalgamated: #include "common/cs_varint.h" */ +#include + /* * Strings in AST are encoded as tuples (length, string). * Length is variable-length: if high bit is set in a byte, next byte is used. * Small string length (less then 128 bytes) is encoded in 1 byte. */ -int64_t cs_varint_decode(const uint8_t *p, int *llen) { - int64_t i = 0, num = 0; +uint64_t cs_varint_decode(const uint8_t *p, int *llen) { + unsigned int i = 0; + unsigned int shift = 0; + uint64_t num = 0; do { /* * Each byte of varint contains 7 bits, in little endian order. * MSB is a continuation bit: it tells whether next byte is used. */ - num |= ((int64_t)(p[i] & 0x7f)) << (7 * i); + num |= ((uint64_t)(p[i] & 0x7f)) << shift; /* * First we increment i, then check whether it is within boundary and * whether decoded byte had continuation bit set. */ - } while ((unsigned int) ++i < sizeof(int64_t) && (p[i - 1] & 0x80)); + i++; + shift += 7; + } while (shift < sizeof(uint64_t) * 8 && (p[i - 1] & 0x80)); *llen = i; return num; } /* Return number of bytes to store length */ -int cs_varint_llen(int64_t num) { +int cs_varint_llen(uint64_t num) { int n = 0; do { @@ -4232,7 +4238,7 @@ int cs_varint_llen(int64_t num) { return n; } -int cs_varint_encode(int64_t num, uint8_t *p) { +int cs_varint_encode(uint64_t num, uint8_t *p) { int i, llen = cs_varint_llen(num); for (i = 0; i < llen; i++) { From 3603a08b9867dda63d2f821f0df4878407847db5 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 23 May 2017 14:04:43 +0300 Subject: [PATCH 005/265] Don't crash on an invalid pointer arithmetic A pointer plus a number yields pointer, but mjs should not crash if the resulting pointer becomes invalid. PUBLISHED_FROM=3bf010a54cf9382dd3e577f9371d67397fbf9b34 --- mjs.c | 37 +++++++++++++++++++++++++++++++------ mjs/src/mjs_ffi.c | 2 +- mjs/src/mjs_object.c | 2 +- mjs/src/mjs_primitive.c | 18 +++++++++++++++--- mjs/src/mjs_primitive.h | 15 ++++++++++++++- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/mjs.c b/mjs.c index 20f6169..f837fb4 100644 --- a/mjs.c +++ b/mjs.c @@ -3053,7 +3053,20 @@ int mjs_is_function(mjs_val_t v); extern "C" { #endif /* __cplusplus */ -MJS_PRIVATE mjs_val_t pointer_to_value(void *p); +/* + * Convert a pointer to mjs_val_t. If pointer is not valid, mjs crashes. + */ +MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p); + +/* + * Convert a pointer to mjs_val_t. If pointer is not valid, error is set + * in the mjs context. + */ +MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p); + +/* + * Extracts a pointer from the mjs_val_t value. + */ MJS_PRIVATE void *get_ptr(mjs_val_t v); #if defined(__cplusplus) @@ -8624,7 +8637,7 @@ MJS_PRIVATE mjs_val_t mjs_ffi_sig_to_value(struct mjs_ffi_sig *psig) { if (psig == NULL) { return MJS_NULL; } else { - return pointer_to_value(psig) | MJS_TAG_FUNCTION_FFI; + return mjs_legit_pointer_to_value(psig) | MJS_TAG_FUNCTION_FFI; } } @@ -10221,7 +10234,7 @@ MJS_PRIVATE mjs_val_t mjs_object_to_value(struct mjs_object *o) { if (o == NULL) { return MJS_NULL; } else { - return pointer_to_value(o) | MJS_TAG_OBJECT; + return mjs_legit_pointer_to_value(o) | MJS_TAG_OBJECT; } } @@ -11523,10 +11536,22 @@ int mjs_is_boolean(mjs_val_t v) { return (v & MJS_TAG_MASK) == MJS_TAG_BOOLEAN; } -MJS_PRIVATE mjs_val_t pointer_to_value(void *p) { +#define MJS_IS_POINTER_LEGIT(n) \ + (((n) &MJS_TAG_MASK) == 0 || ((n) &MJS_TAG_MASK) == (~0 & MJS_TAG_MASK)) + +MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p) { + uint64_t n = ((uint64_t)(uintptr_t) p); + + if (!MJS_IS_POINTER_LEGIT(n)) { + mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid pointer value: %p", p); + } + return n & ~MJS_TAG_MASK; +} + +MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p) { uint64_t n = ((uint64_t)(uintptr_t) p); - assert((n & MJS_TAG_MASK) == 0 || (n & MJS_TAG_MASK) == (~0 & MJS_TAG_MASK)); + assert(MJS_IS_POINTER_LEGIT(n)); return n & ~MJS_TAG_MASK; } @@ -11544,7 +11569,7 @@ void *mjs_get_ptr(struct mjs *mjs, mjs_val_t v) { mjs_val_t mjs_mk_foreign(struct mjs *mjs, void *p) { (void) mjs; - return pointer_to_value(p) | MJS_TAG_FOREIGN; + return mjs_pointer_to_value(mjs, p) | MJS_TAG_FOREIGN; } int mjs_is_foreign(mjs_val_t v) { diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index c97eab2..c56b39c 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -493,7 +493,7 @@ MJS_PRIVATE mjs_val_t mjs_ffi_sig_to_value(struct mjs_ffi_sig *psig) { if (psig == NULL) { return MJS_NULL; } else { - return pointer_to_value(psig) | MJS_TAG_FUNCTION_FFI; + return mjs_legit_pointer_to_value(psig) | MJS_TAG_FUNCTION_FFI; } } diff --git a/mjs/src/mjs_object.c b/mjs/src/mjs_object.c index c8d422e..2de7796 100644 --- a/mjs/src/mjs_object.c +++ b/mjs/src/mjs_object.c @@ -15,7 +15,7 @@ MJS_PRIVATE mjs_val_t mjs_object_to_value(struct mjs_object *o) { if (o == NULL) { return MJS_NULL; } else { - return pointer_to_value(o) | MJS_TAG_OBJECT; + return mjs_legit_pointer_to_value(o) | MJS_TAG_OBJECT; } } diff --git a/mjs/src/mjs_primitive.c b/mjs/src/mjs_primitive.c index 906a173..807dd78 100644 --- a/mjs/src/mjs_primitive.c +++ b/mjs/src/mjs_primitive.c @@ -91,10 +91,22 @@ int mjs_is_boolean(mjs_val_t v) { return (v & MJS_TAG_MASK) == MJS_TAG_BOOLEAN; } -MJS_PRIVATE mjs_val_t pointer_to_value(void *p) { +#define MJS_IS_POINTER_LEGIT(n) \ + (((n) &MJS_TAG_MASK) == 0 || ((n) &MJS_TAG_MASK) == (~0 & MJS_TAG_MASK)) + +MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p) { + uint64_t n = ((uint64_t)(uintptr_t) p); + + if (!MJS_IS_POINTER_LEGIT(n)) { + mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid pointer value: %p", p); + } + return n & ~MJS_TAG_MASK; +} + +MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p) { uint64_t n = ((uint64_t)(uintptr_t) p); - assert((n & MJS_TAG_MASK) == 0 || (n & MJS_TAG_MASK) == (~0 & MJS_TAG_MASK)); + assert(MJS_IS_POINTER_LEGIT(n)); return n & ~MJS_TAG_MASK; } @@ -112,7 +124,7 @@ void *mjs_get_ptr(struct mjs *mjs, mjs_val_t v) { mjs_val_t mjs_mk_foreign(struct mjs *mjs, void *p) { (void) mjs; - return pointer_to_value(p) | MJS_TAG_FOREIGN; + return mjs_pointer_to_value(mjs, p) | MJS_TAG_FOREIGN; } int mjs_is_foreign(mjs_val_t v) { diff --git a/mjs/src/mjs_primitive.h b/mjs/src/mjs_primitive.h index a7d2e41..3ea1e80 100644 --- a/mjs/src/mjs_primitive.h +++ b/mjs/src/mjs_primitive.h @@ -13,7 +13,20 @@ extern "C" { #endif /* __cplusplus */ -MJS_PRIVATE mjs_val_t pointer_to_value(void *p); +/* + * Convert a pointer to mjs_val_t. If pointer is not valid, mjs crashes. + */ +MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p); + +/* + * Convert a pointer to mjs_val_t. If pointer is not valid, error is set + * in the mjs context. + */ +MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p); + +/* + * Extracts a pointer from the mjs_val_t value. + */ MJS_PRIVATE void *get_ptr(mjs_val_t v); #if defined(__cplusplus) From 2dd7644d14358f7b9ebaa0b8d24672fceb0e7bef Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 23 May 2017 19:33:35 +0300 Subject: [PATCH 006/265] Implement short-circuit evaluation for && and || PUBLISHED_FROM=4589803544e77d2ea40c107e9e98bbe760a14fad --- mjs.c | 157 ++++++++++++++++++++++++++---------------- mjs/src/mjs_bcode.h | 60 ++++++++-------- mjs/src/mjs_exec.c | 39 +++++++---- mjs/src/mjs_parser.c | 39 ++++++++--- mjs/src/mjs_util.c | 19 ++--- mjs/tests/unit_test.c | 8 +++ 6 files changed, 200 insertions(+), 122 deletions(-) diff --git a/mjs.c b/mjs.c index f837fb4..1daac15 100644 --- a/mjs.c +++ b/mjs.c @@ -3324,35 +3324,37 @@ extern "C" { #endif /* __cplusplus */ enum mjs_opcode { - OP_NOP, /* ( -- ) */ - OP_DROP, /* ( a -- ) */ - OP_DUP, /* ( a -- a a ) */ - OP_SWAP, /* ( a b -- b a ) */ - OP_JMP, /* ( -- ) */ - OP_JMP_TRUE, /* ( -- ) */ - OP_JMP_FALSE, /* ( -- ) */ - OP_FIND_SCOPE, /* ( a -- a b ) */ - OP_PUSH_SCOPE, /* ( -- a ) */ - OP_PUSH_STR, /* ( -- a ) */ - OP_PUSH_TRUE, /* ( -- a ) */ - OP_PUSH_FALSE, /* ( -- a ) */ - OP_PUSH_INT, /* ( -- a ) */ - OP_PUSH_DBL, /* ( -- a ) */ - OP_PUSH_NULL, /* ( -- a ) */ - OP_PUSH_UNDEF, /* ( -- a ) */ - OP_PUSH_OBJ, /* ( -- a ) */ - OP_PUSH_ARRAY, /* ( -- a ) */ - OP_PUSH_FUNC, /* ( -- a ) */ - OP_PUSH_THIS, /* ( -- a ) */ - OP_GET, /* ( key obj -- obj[key] ) */ - OP_CREATE, /* ( key obj -- ) */ - OP_EXPR, /* ( ... -- a ) */ - OP_APPEND, /* ( a b -- ) */ - OP_SET_ARG, /* ( a -- a ) */ - OP_NEW_SCOPE, /* ( -- ) */ - OP_DEL_SCOPE, /* ( -- ) */ - OP_CALL, /* ( func param1 param2 ... num_params -- result ) */ - OP_RETURN, /* ( -- ) */ + OP_NOP, /* ( -- ) */ + OP_DROP, /* ( a -- ) */ + OP_DUP, /* ( a -- a a ) */ + OP_SWAP, /* ( a b -- b a ) */ + OP_JMP, /* ( -- ) */ + OP_JMP_TRUE, /* ( -- ) */ + OP_JMP_NEUTRAL_TRUE, /* ( -- ) */ + OP_JMP_FALSE, /* ( -- ) */ + OP_JMP_NEUTRAL_FALSE, /* ( -- ) */ + OP_FIND_SCOPE, /* ( a -- a b ) */ + OP_PUSH_SCOPE, /* ( -- a ) */ + OP_PUSH_STR, /* ( -- a ) */ + OP_PUSH_TRUE, /* ( -- a ) */ + OP_PUSH_FALSE, /* ( -- a ) */ + OP_PUSH_INT, /* ( -- a ) */ + OP_PUSH_DBL, /* ( -- a ) */ + OP_PUSH_NULL, /* ( -- a ) */ + OP_PUSH_UNDEF, /* ( -- a ) */ + OP_PUSH_OBJ, /* ( -- a ) */ + OP_PUSH_ARRAY, /* ( -- a ) */ + OP_PUSH_FUNC, /* ( -- a ) */ + OP_PUSH_THIS, /* ( -- a ) */ + OP_GET, /* ( key obj -- obj[key] ) */ + OP_CREATE, /* ( key obj -- ) */ + OP_EXPR, /* ( ... -- a ) */ + OP_APPEND, /* ( a b -- ) */ + OP_SET_ARG, /* ( a -- a ) */ + OP_NEW_SCOPE, /* ( -- ) */ + OP_DEL_SCOPE, /* ( -- ) */ + OP_CALL, /* ( func param1 param2 ... num_params -- result ) */ + OP_RETURN, /* ( -- ) */ OP_LOOP, /* ( -- ) Push break & continue addresses to loop_labels */ OP_BREAK, /* ( -- ) */ OP_CONTINUE, /* ( -- ) */ @@ -7442,18 +7444,12 @@ static void exec_expr(struct mjs *mjs, int op) { } break; } - case TOK_LOGICAL_AND: { - mjs_val_t b = mjs_pop(mjs); - mjs_val_t a = mjs_pop(mjs); - mjs_push(mjs, mjs_is_truthy(mjs, a) ? b : a); - break; - } - case TOK_LOGICAL_OR: { - mjs_val_t b = mjs_pop(mjs); - mjs_val_t a = mjs_pop(mjs); - mjs_push(mjs, mjs_is_truthy(mjs, a) ? a : b); - break; - } + /* + * NOTE: TOK_LOGICAL_AND and TOK_LOGICAL_OR don't need to be here, because + * they are just naturally handled by the short-circuit evaluation. + * See PARSE_LTR_BINOP() macro in mjs_parser.c. + */ + /* clang-format off */ case TOK_MINUS_ASSIGN: op_assign(mjs, TOK_MINUS); break; case TOK_PLUS_ASSIGN: op_assign(mjs, TOK_PLUS); break; @@ -7665,6 +7661,27 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { } break; } + /* + * OP_JMP_NEUTRAL_... ops are like as OP_JMP_..., but they are completely + * stack-neutral: they just check the TOS, and increment instruction + * pointer if the TOS is truthy/falsy. + */ + case OP_JMP_NEUTRAL_TRUE: { + int llen, n = cs_varint_decode(&code[i + 1], &llen); + i += llen; + if (mjs_is_truthy(mjs, vtop(&mjs->stack))) { + i += n; + } + break; + } + case OP_JMP_NEUTRAL_FALSE: { + int llen, n = cs_varint_decode(&code[i + 1], &llen); + i += llen; + if (!mjs_is_truthy(mjs, vtop(&mjs->stack))) { + i += n; + } + break; + } case OP_FIND_SCOPE: { mjs_val_t key = vtop(&mjs->stack); mjs_push(mjs, mjs_find_scope(mjs, key)); @@ -10573,17 +10590,34 @@ static void emit_op(struct pstate *pstate, int tok) { // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. -#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ - do { \ - mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ - if (prev_op != TOK_EOF) emit_op(p, prev_op); \ - if (findtok(ops, p->tok.tok) != TOK_EOF) { \ - int op = p->tok.tok; \ - pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ - } \ - return res; \ +#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ + do { \ + mjs_err_t res = MJS_OK; \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + if (prev_op != TOK_EOF) emit_op(p, prev_op); \ + if (findtok(ops, p->tok.tok) != TOK_EOF) { \ + int op = p->tok.tok; \ + size_t off_if = 0; \ + /* For AND/OR, implement short-circuit evaluation */ \ + if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ + emit_byte(p, ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ + : OP_JMP_NEUTRAL_TRUE); \ + off_if = p->cur_idx; \ + emit_init_offset(p); \ + /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ + /* Just drop the first value, and evaluate the second one. */ \ + emit_byte(p, OP_DROP); \ + op = TOK_EOF; \ + } \ + pnext1(p); \ + if ((res = f2(p, op)) != MJS_OK) return res; \ + \ + if (off_if != 0) { \ + mjs_bcode_insert_offset(p, p->mjs, off_if, \ + p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ + } \ + } \ + return res; \ } while (0) #define PARSE_RTL_BINOP(p, f1, f2, ops, prev_op) \ @@ -12436,14 +12470,13 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { static const char *names[] = { - "NOP", "DROP", "DUP", "SWAP", "JMP", - "JMP_TRUE", "JMP_FALSE", "FIND_SCOPE", "PUSH_SCOPE", "PUSH_STR", - "PUSH_TRUE", "PUSH_FALSE", "PUSH_INT", "PUSH_DBL", "PUSH_NULL", - "PUSH_UNDEF", "PUSH_OBJ", "PUSH_ARRAY", "PUSH_FUNC", "PUSH_THIS", - "GET", "CREATE", "EXPR", "APPEND", "SET_ARG", - "NEW_SCOPE", "DEL_SCOPE", "CALL", "RETURN", "LOOP", - "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", - "ARGS", "FOR_IN_NEXT", + "NOP", "DROP", "DUP", "SWAP", "JMP", "JMP_TRUE", "JMP_NEUTRAL_TRUE", + "JMP_FALSE", "JMP_NEUTRAL_FALSE", "FIND_SCOPE", "PUSH_SCOPE", "PUSH_STR", + "PUSH_TRUE", "PUSH_FALSE", "PUSH_INT", "PUSH_DBL", "PUSH_NULL", + "PUSH_UNDEF", "PUSH_OBJ", "PUSH_ARRAY", "PUSH_FUNC", "PUSH_THIS", "GET", + "CREATE", "EXPR", "APPEND", "SET_ARG", "NEW_SCOPE", "DEL_SCOPE", "CALL", + "RETURN", "LOOP", "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", + "ARGS", "FOR_IN_NEXT", }; const char *name = "UNKNOWN OPCODE"; assert(ARRAY_SIZE(names) == OP_MAX); @@ -12485,7 +12518,9 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { } case OP_JMP: case OP_JMP_TRUE: - case OP_JMP_FALSE: { + case OP_JMP_NEUTRAL_TRUE: + case OP_JMP_FALSE: + case OP_JMP_NEUTRAL_FALSE: { int llen, n = cs_varint_decode(&code[i + 1], &llen); fprintf(fp, "\t%u", (unsigned) i + n + llen + diff --git a/mjs/src/mjs_bcode.h b/mjs/src/mjs_bcode.h index 31d31c4..4f0e0bc 100644 --- a/mjs/src/mjs_bcode.h +++ b/mjs/src/mjs_bcode.h @@ -15,35 +15,37 @@ extern "C" { #endif /* __cplusplus */ enum mjs_opcode { - OP_NOP, /* ( -- ) */ - OP_DROP, /* ( a -- ) */ - OP_DUP, /* ( a -- a a ) */ - OP_SWAP, /* ( a b -- b a ) */ - OP_JMP, /* ( -- ) */ - OP_JMP_TRUE, /* ( -- ) */ - OP_JMP_FALSE, /* ( -- ) */ - OP_FIND_SCOPE, /* ( a -- a b ) */ - OP_PUSH_SCOPE, /* ( -- a ) */ - OP_PUSH_STR, /* ( -- a ) */ - OP_PUSH_TRUE, /* ( -- a ) */ - OP_PUSH_FALSE, /* ( -- a ) */ - OP_PUSH_INT, /* ( -- a ) */ - OP_PUSH_DBL, /* ( -- a ) */ - OP_PUSH_NULL, /* ( -- a ) */ - OP_PUSH_UNDEF, /* ( -- a ) */ - OP_PUSH_OBJ, /* ( -- a ) */ - OP_PUSH_ARRAY, /* ( -- a ) */ - OP_PUSH_FUNC, /* ( -- a ) */ - OP_PUSH_THIS, /* ( -- a ) */ - OP_GET, /* ( key obj -- obj[key] ) */ - OP_CREATE, /* ( key obj -- ) */ - OP_EXPR, /* ( ... -- a ) */ - OP_APPEND, /* ( a b -- ) */ - OP_SET_ARG, /* ( a -- a ) */ - OP_NEW_SCOPE, /* ( -- ) */ - OP_DEL_SCOPE, /* ( -- ) */ - OP_CALL, /* ( func param1 param2 ... num_params -- result ) */ - OP_RETURN, /* ( -- ) */ + OP_NOP, /* ( -- ) */ + OP_DROP, /* ( a -- ) */ + OP_DUP, /* ( a -- a a ) */ + OP_SWAP, /* ( a b -- b a ) */ + OP_JMP, /* ( -- ) */ + OP_JMP_TRUE, /* ( -- ) */ + OP_JMP_NEUTRAL_TRUE, /* ( -- ) */ + OP_JMP_FALSE, /* ( -- ) */ + OP_JMP_NEUTRAL_FALSE, /* ( -- ) */ + OP_FIND_SCOPE, /* ( a -- a b ) */ + OP_PUSH_SCOPE, /* ( -- a ) */ + OP_PUSH_STR, /* ( -- a ) */ + OP_PUSH_TRUE, /* ( -- a ) */ + OP_PUSH_FALSE, /* ( -- a ) */ + OP_PUSH_INT, /* ( -- a ) */ + OP_PUSH_DBL, /* ( -- a ) */ + OP_PUSH_NULL, /* ( -- a ) */ + OP_PUSH_UNDEF, /* ( -- a ) */ + OP_PUSH_OBJ, /* ( -- a ) */ + OP_PUSH_ARRAY, /* ( -- a ) */ + OP_PUSH_FUNC, /* ( -- a ) */ + OP_PUSH_THIS, /* ( -- a ) */ + OP_GET, /* ( key obj -- obj[key] ) */ + OP_CREATE, /* ( key obj -- ) */ + OP_EXPR, /* ( ... -- a ) */ + OP_APPEND, /* ( a b -- ) */ + OP_SET_ARG, /* ( a -- a ) */ + OP_NEW_SCOPE, /* ( -- ) */ + OP_DEL_SCOPE, /* ( -- ) */ + OP_CALL, /* ( func param1 param2 ... num_params -- result ) */ + OP_RETURN, /* ( -- ) */ OP_LOOP, /* ( -- ) Push break & continue addresses to loop_labels */ OP_BREAK, /* ( -- ) */ OP_CONTINUE, /* ( -- ) */ diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 1610d06..75cba30 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -355,18 +355,12 @@ static void exec_expr(struct mjs *mjs, int op) { } break; } - case TOK_LOGICAL_AND: { - mjs_val_t b = mjs_pop(mjs); - mjs_val_t a = mjs_pop(mjs); - mjs_push(mjs, mjs_is_truthy(mjs, a) ? b : a); - break; - } - case TOK_LOGICAL_OR: { - mjs_val_t b = mjs_pop(mjs); - mjs_val_t a = mjs_pop(mjs); - mjs_push(mjs, mjs_is_truthy(mjs, a) ? a : b); - break; - } + /* + * NOTE: TOK_LOGICAL_AND and TOK_LOGICAL_OR don't need to be here, because + * they are just naturally handled by the short-circuit evaluation. + * See PARSE_LTR_BINOP() macro in mjs_parser.c. + */ + /* clang-format off */ case TOK_MINUS_ASSIGN: op_assign(mjs, TOK_MINUS); break; case TOK_PLUS_ASSIGN: op_assign(mjs, TOK_PLUS); break; @@ -578,6 +572,27 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { } break; } + /* + * OP_JMP_NEUTRAL_... ops are like as OP_JMP_..., but they are completely + * stack-neutral: they just check the TOS, and increment instruction + * pointer if the TOS is truthy/falsy. + */ + case OP_JMP_NEUTRAL_TRUE: { + int llen, n = cs_varint_decode(&code[i + 1], &llen); + i += llen; + if (mjs_is_truthy(mjs, vtop(&mjs->stack))) { + i += n; + } + break; + } + case OP_JMP_NEUTRAL_FALSE: { + int llen, n = cs_varint_decode(&code[i + 1], &llen); + i += llen; + if (!mjs_is_truthy(mjs, vtop(&mjs->stack))) { + i += n; + } + break; + } case OP_FIND_SCOPE: { mjs_val_t key = vtop(&mjs->stack); mjs_push(mjs, mjs_find_scope(mjs, key)); diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index 68f0c8a..9e66ffa 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -72,17 +72,34 @@ static void emit_op(struct pstate *pstate, int tok) { // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. -#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ - do { \ - mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ - if (prev_op != TOK_EOF) emit_op(p, prev_op); \ - if (findtok(ops, p->tok.tok) != TOK_EOF) { \ - int op = p->tok.tok; \ - pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ - } \ - return res; \ +#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ + do { \ + mjs_err_t res = MJS_OK; \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + if (prev_op != TOK_EOF) emit_op(p, prev_op); \ + if (findtok(ops, p->tok.tok) != TOK_EOF) { \ + int op = p->tok.tok; \ + size_t off_if = 0; \ + /* For AND/OR, implement short-circuit evaluation */ \ + if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ + emit_byte(p, ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ + : OP_JMP_NEUTRAL_TRUE); \ + off_if = p->cur_idx; \ + emit_init_offset(p); \ + /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ + /* Just drop the first value, and evaluate the second one. */ \ + emit_byte(p, OP_DROP); \ + op = TOK_EOF; \ + } \ + pnext1(p); \ + if ((res = f2(p, op)) != MJS_OK) return res; \ + \ + if (off_if != 0) { \ + mjs_bcode_insert_offset(p, p->mjs, off_if, \ + p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ + } \ + } \ + return res; \ } while (0) #define PARSE_RTL_BINOP(p, f1, f2, ops, prev_op) \ diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index 40eca34..42366b9 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -79,14 +79,13 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { static const char *names[] = { - "NOP", "DROP", "DUP", "SWAP", "JMP", - "JMP_TRUE", "JMP_FALSE", "FIND_SCOPE", "PUSH_SCOPE", "PUSH_STR", - "PUSH_TRUE", "PUSH_FALSE", "PUSH_INT", "PUSH_DBL", "PUSH_NULL", - "PUSH_UNDEF", "PUSH_OBJ", "PUSH_ARRAY", "PUSH_FUNC", "PUSH_THIS", - "GET", "CREATE", "EXPR", "APPEND", "SET_ARG", - "NEW_SCOPE", "DEL_SCOPE", "CALL", "RETURN", "LOOP", - "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", - "ARGS", "FOR_IN_NEXT", + "NOP", "DROP", "DUP", "SWAP", "JMP", "JMP_TRUE", "JMP_NEUTRAL_TRUE", + "JMP_FALSE", "JMP_NEUTRAL_FALSE", "FIND_SCOPE", "PUSH_SCOPE", "PUSH_STR", + "PUSH_TRUE", "PUSH_FALSE", "PUSH_INT", "PUSH_DBL", "PUSH_NULL", + "PUSH_UNDEF", "PUSH_OBJ", "PUSH_ARRAY", "PUSH_FUNC", "PUSH_THIS", "GET", + "CREATE", "EXPR", "APPEND", "SET_ARG", "NEW_SCOPE", "DEL_SCOPE", "CALL", + "RETURN", "LOOP", "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", + "ARGS", "FOR_IN_NEXT", }; const char *name = "UNKNOWN OPCODE"; assert(ARRAY_SIZE(names) == OP_MAX); @@ -128,7 +127,9 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { } case OP_JMP: case OP_JMP_TRUE: - case OP_JMP_FALSE: { + case OP_JMP_NEUTRAL_TRUE: + case OP_JMP_FALSE: + case OP_JMP_NEUTRAL_FALSE: { int llen, n = cs_varint_decode(&code[i + 1], &llen); fprintf(fp, "\t%u", (unsigned) i + n + llen + diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index ccea04d..b2e0be2 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -481,6 +481,14 @@ const char *test_logic(struct mjs *mjs) { ASSERT_EQ(mjs_is_boolean(res), 0); ASSERT_EQ(mjs_get_double(mjs, res), 1); + /* Test short-circuit for && */ + ASSERT_EXEC_OK(mjs_exec(mjs, "let a=1, b=2, c=0; if (a > 1 && (b = b+1) > 2) { c=b; } b", &res)); + ASSERT_EQ(mjs_get_double(mjs, res), 2); + + /* Test short-circuit for || */ + ASSERT_EXEC_OK(mjs_exec(mjs, "let a=1, b=2, c=0; if (a === 1 || (b = b+1) > 2) { c=b; } b", &res)); + ASSERT_EQ(mjs_get_double(mjs, res), 2); + mjs_disown(mjs, &res); return NULL; From f8c37a2cd47d5764a80a0a73e619cc1759b97b74 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 25 May 2017 18:05:18 +0100 Subject: [PATCH 007/265] ESP8266 and ESP32 build image updates ESP32: 2.0-r6 ESP8266: 2.0.0-1.5.0-r5 This brings updated mbedTLS with support for on-disk CA chains: https://github.com/cesanta/mbedtls/compare/esp32_2.0-r5...esp32_2.0-r6 ESP8266 gets bigger rollup (ESP32 got those changes earlier, seems ok): https://github.com/cesanta/mbedtls/compare/esp8266...esp8266_2.0.0-1.5.0-r5 Saves ~1.5K RAM for now, but will allow adding more roots to ca.pem without wasting RAM. Refactored docker build for ESP8266 in the same way as was done earlier for ESP32. PUBLISHED_FROM=db8eb0f91875d02266a8baaf1141c0d65eb59674 --- common/platforms/esp8266/esp_crypto.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/common/platforms/esp8266/esp_crypto.c b/common/platforms/esp8266/esp_crypto.c index 3f213b7..4ed40ae 100644 --- a/common/platforms/esp8266/esp_crypto.c +++ b/common/platforms/esp8266/esp_crypto.c @@ -78,16 +78,18 @@ int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, return 0; } -void mbedtls_aes_encrypt(mbedtls_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16]) { +int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16]) { aes_encrypt(ctx, input, output); + return 0; } -void mbedtls_aes_decrypt(mbedtls_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16]) { +int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16]) { aes_decrypt(ctx, input, output); + return 0; } /* os_get_random uses hardware RNG, so it's cool. */ From fb6f59456a61de8eee229b012a3ede353afd06fa Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 30 May 2017 12:51:57 +0100 Subject: [PATCH 008/265] Annotate cs_log_printf with format attribute This adds compile-time checks for format strings. Fix issues exposed by this. PUBLISHED_FROM=3e901d3c5373dda800ed518c492be34ad64a8a5b --- common/cs_dbg.h | 6 +++++- common/platforms/lwip/mg_lwip_ev_mgr.c | 2 +- common/platforms/lwip/mg_lwip_net_if.c | 4 ++-- common/platforms/lwip/mg_lwip_ssl_if.c | 2 +- mjs.c | 6 +++++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/common/cs_dbg.h b/common/cs_dbg.h index c75f6b0..cca04a3 100644 --- a/common/cs_dbg.h +++ b/common/cs_dbg.h @@ -43,7 +43,11 @@ void cs_log_set_level(enum cs_log_level level); void cs_log_set_file(FILE *file); extern enum cs_log_level cs_log_threshold; void cs_log_print_prefix(enum cs_log_level level, const char *func); -void cs_log_printf(const char *fmt, ...); +void cs_log_printf(const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 1, 2))) +#endif + ; #define LOG(l, x) \ do { \ diff --git a/common/platforms/lwip/mg_lwip_ev_mgr.c b/common/platforms/lwip/mg_lwip_ev_mgr.c index c2edc1e..7c4c8bf 100644 --- a/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -87,7 +87,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } void mg_lwip_if_init(struct mg_iface *iface) { - LOG(LL_INFO, ("%p Mongoose init")); + LOG(LL_INFO, ("%p Mongoose init", iface)); iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data)); } diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 30247a5..681a343 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -215,10 +215,10 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent) { struct mg_connection *nc = (struct mg_connection *) arg; - DBG(("%p %p %u %u %u", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked)); + DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked)); if (nc == NULL) return ERR_OK; if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) && - nc->send_mbuf.len == 0 && tpcb->unsent == 0 && tpcb->unacked == 0) { + nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } return ERR_OK; diff --git a/common/platforms/lwip/mg_lwip_ssl_if.c b/common/platforms/lwip/mg_lwip_ssl_if.c index bc61b8e..fded431 100644 --- a/common/platforms/lwip/mg_lwip_ssl_if.c +++ b/common/platforms/lwip/mg_lwip_ssl_if.c @@ -33,7 +33,7 @@ void mg_lwip_ssl_do_hs(struct mg_connection *nc) { enum mg_ssl_if_result res; if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return; res = mg_ssl_if_handshake(nc); - DBG(("%p %d %d %d", nc, nc->flags, server_side, res)); + DBG(("%p %lu %d %d", nc, nc->flags, server_side, res)); if (res != MG_SSL_OK) { if (res == MG_SSL_WANT_WRITE) { nc->flags |= MG_F_WANT_WRITE; diff --git a/mjs.c b/mjs.c index 1daac15..4e7842b 100644 --- a/mjs.c +++ b/mjs.c @@ -1414,7 +1414,11 @@ void cs_log_set_level(enum cs_log_level level); void cs_log_set_file(FILE *file); extern enum cs_log_level cs_log_threshold; void cs_log_print_prefix(enum cs_log_level level, const char *func); -void cs_log_printf(const char *fmt, ...); +void cs_log_printf(const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 1, 2))) +#endif + ; #define LOG(l, x) \ do { \ From 9d4cab915a572e67580d6f0e2b5f50b0658aa217 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 31 May 2017 14:43:10 +0100 Subject: [PATCH 009/265] Fix ffi-ing strings as void pointer Short strings (which are packed into mjs_val_t itself) weren't handled correctly PUBLISHED_FROM=75b4108917c2346ba7a36e26460a9954907f867a --- mjs.c | 16 +++++++++++++++- mjs/src/mjs_ffi.c | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index 4e7842b..dca1425 100644 --- a/mjs.c +++ b/mjs.c @@ -8722,6 +8722,11 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { /* TODO(dfrank): support multiple callbacks */ mjs_val_t resv = mjs_mk_undefined(); + + /* + * String arguments, needed to support short strings which are packed into + * mjs_val_t itself + */ mjs_val_t argvs[FFI_MAX_ARGS_CNT]; if (mjs_is_ffi_sig(sig_v)) { @@ -8845,6 +8850,10 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { i, mjs_typeof(arg)); goto clean; } + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ argvs[i] = arg; ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &s)); } break; @@ -8856,7 +8865,12 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } if (mjs_is_string(arg)) { size_t n; - ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &arg, &n)); + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ + argvs[i] = arg; + ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &n)); } else { ffi_set_ptr(&args[i], (void *) mjs_get_ptr(mjs, arg)); } diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index c56b39c..52cb6b1 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -557,6 +557,11 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { /* TODO(dfrank): support multiple callbacks */ mjs_val_t resv = mjs_mk_undefined(); + + /* + * String arguments, needed to support short strings which are packed into + * mjs_val_t itself + */ mjs_val_t argvs[FFI_MAX_ARGS_CNT]; if (mjs_is_ffi_sig(sig_v)) { @@ -680,6 +685,10 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { i, mjs_typeof(arg)); goto clean; } + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ argvs[i] = arg; ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &s)); } break; @@ -691,7 +700,12 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } if (mjs_is_string(arg)) { size_t n; - ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &arg, &n)); + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ + argvs[i] = arg; + ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &n)); } else { ffi_set_ptr(&args[i], (void *) mjs_get_ptr(mjs, arg)); } From b32a1315ce4d034605a099315bf8adcea938f44a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 1 Jun 2017 00:57:58 +0100 Subject: [PATCH 010/265] Run flash at 40 MHz during flashing Default is 10 MHz. Makes it slightly faster. Update stub for newer build image. PUBLISHED_FROM=a1c4f1f22341136e06717ecc1936142f056234a9 --- common/platforms/esp/stub_flasher.c | 37 ++++--- common/platforms/esp32/rom/ESP32_ROM.txt | 88 +++++++-------- common/platforms/esp32/rom/rom.S | 2 + common/platforms/esp32/rom/rom.elf | Bin 521844 -> 521912 bytes common/platforms/esp32/stubs/Makefile | 1 + common/platforms/esp32/stubs/sdkconfig.h | 1 + common/platforms/esp32/stubs/spi_flash.c | 102 ------------------ common/platforms/esp32/stubs/stub.ld | 3 + .../platforms/esp8266/stubs/rom_functions.h | 9 ++ 9 files changed, 85 insertions(+), 158 deletions(-) create mode 100644 common/platforms/esp32/stubs/sdkconfig.h delete mode 100644 common/platforms/esp32/stubs/spi_flash.c diff --git a/common/platforms/esp/stub_flasher.c b/common/platforms/esp/stub_flasher.c index f1ad80d..c0c5c12 100644 --- a/common/platforms/esp/stub_flasher.c +++ b/common/platforms/esp/stub_flasher.c @@ -61,22 +61,24 @@ extern uint32_t _bss_start, _bss_end; int do_flash_erase(uint32_t addr, uint32_t len) { if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; if (len % FLASH_SECTOR_SIZE != 0) return 0x33; - if (SPIUnlock() != 0) return 0x34; + if (esp_rom_spiflash_unlock() != 0) return 0x34; while (len > 0 && (addr % FLASH_BLOCK_SIZE != 0)) { - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) + return 0x35; len -= FLASH_SECTOR_SIZE; addr += FLASH_SECTOR_SIZE; } while (len > FLASH_BLOCK_SIZE) { - if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; + if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; len -= FLASH_BLOCK_SIZE; addr += FLASH_BLOCK_SIZE; } while (len > 0) { - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; + if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) + return 0x37; len -= FLASH_SECTOR_SIZE; addr += FLASH_SECTOR_SIZE; } @@ -134,7 +136,7 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; if (len % FLASH_SECTOR_SIZE != 0) return 0x33; - if (SPIUnlock() != 0) return 0x34; + if (esp_rom_spiflash_unlock() != 0) return 0x34; ub.nr = 0; ub.pr = ub.pw = ub.data; @@ -160,11 +162,13 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { while (erase && num_erased < wp.num_written + FLASH_WRITE_SIZE) { const uint32_t num_left = (len - num_erased); if (num_left >= FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) { - if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x35; + if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) + return 0x35; num_erased += FLASH_BLOCK_SIZE; } else { /* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */ - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x36; + if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) + return 0x36; num_erased += FLASH_SECTOR_SIZE; } } @@ -177,7 +181,8 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { wr.wait_time += ccount() - start_count; MD5Update(&ctx, ub.pr, FLASH_WRITE_SIZE); start_count = ccount(); - if (SPIWrite(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != 0) return 0x37; + if (esp_rom_spiflash_write(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != 0) + return 0x37; wr.write_time += ccount() - start_count; ets_intr_lock(); *nr -= FLASH_WRITE_SIZE; @@ -211,7 +216,7 @@ int do_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, while (num_sent < len && num_sent - num_acked < max_in_flight) { uint32_t n = len - num_sent; if (n > block_size) n = block_size; - if (SPIRead(addr, (uint32_t *) buf, n) != 0) return 0x53; + if (esp_rom_spiflash_read(addr, (uint32_t *) buf, n) != 0) return 0x53; send_packet(buf, n); MD5Update(&ctx, buf, n); addr += n; @@ -240,7 +245,7 @@ int do_flash_digest(uint32_t addr, uint32_t len, uint32_t digest_block_size) { struct MD5Context block_ctx; MD5Init(&block_ctx); if (n > read_block_size) n = read_block_size; - if (SPIRead(addr, (uint32_t *) buf, n) != 0) return 0x63; + if (esp_rom_spiflash_read(addr, (uint32_t *) buf, n) != 0) return 0x63; MD5Update(&ctx, buf, n); if (digest_block_size > 0) { MD5Update(&block_ctx, buf, n); @@ -320,7 +325,7 @@ uint8_t cmd_loop(void) { break; } case CMD_FLASH_ERASE_CHIP: { - resp = SPIEraseChip(); + resp = esp_rom_spiflash_erase_chip(); break; } case CMD_BOOT_FW: @@ -350,11 +355,15 @@ void stub_main(void) { SelectSpiFunction(); SET_PERI_REG_MASK(0x3FF00014, 1); /* Switch to 160 MHz */ #elif defined(ESP32) - spi_flash_attach(0, 0); + esp_rom_spiflash_attach(0 /* ishspi */, 0 /* legacy */); + /* Set flash to 40 MHz. Note: clkdiv _should_ be 2, but actual meausrement + * shows that with clkdiv = 1 clock is indeed 40 MHz. */ + esp_rom_spiflash_config_clk(1, 1); #endif - SPIParamCfg(0, 16 * 1024 * 1024, FLASH_BLOCK_SIZE, FLASH_SECTOR_SIZE, - FLASH_PAGE_SIZE, 0xffff); + esp_rom_spiflash_config_param( + 0 /* deviceId */, 16 * 1024 * 1024 /* chip_size */, FLASH_BLOCK_SIZE, + FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE, 0xffff /* status_mask */); if (baud_rate > 0) { ets_delay_us(10000); diff --git a/common/platforms/esp32/rom/ESP32_ROM.txt b/common/platforms/esp32/rom/ESP32_ROM.txt index 632f09a..08b1b41 100644 --- a/common/platforms/esp32/rom/ESP32_ROM.txt +++ b/common/platforms/esp32/rom/ESP32_ROM.txt @@ -152991,13 +152991,15 @@ Disassembly of section .text: 40061b80: 000000 ill 40061b83: 000020 lsi f2, a0, 0 40061b86: 365000 lsi f0, a0, 216 -40061b89: b10041 l32r a4, 4004df8c -40061b8c: 81fff4 lsi f15, a15, 0x204 -40061b8f: b0fff4 lsi f15, a15, 0x2c0 -40061b92: a110c2 l16ui a12, a0, 0x142 -40061b95: 9168e1 l32r a14, 40046138 -40061b98: b7fff6 bgeui a15, 0x100, 40061b53 -40061b9b: 669c beqz.n a6, 40061bb5 + +40061b88 <_x_unk_40061b88>: +40061b88: 004136 entry a1, 32 +40061b8b: fff4b1 l32r a11, 40061b5c +40061b8e: fff481 l32r a8, 40061b60 +40061b91: 10c2b0 and a12, a2, a11 +40061b94: 68e1a1 l32r a10, 4003bf18 +40061b97: fff691 l32r a9, 40061b70 +40061b9a: 669cb7 bne a12, a11, 40061c04 <_x_unk_40061b88+0x7c> 40061b9d: 0020c0 memw 40061ba0: 0828 l32i.n a2, a8, 0 40061ba2: 10a2a0 and a10, a2, a10 @@ -153034,7 +153036,7 @@ Disassembly of section .text: 40061bf7: 0298 l32i.n a9, a2, 0 40061bf9: 108980 and a8, a9, a8 40061bfc: eba092 movi a9, 235 -40061bff: 005f86 j 40061d81 +40061bff: 005f86 j 40061d81 <_x_unk_40061b88+0x1f9> 40061c02: d70000 lsi f0, a0, 0x35c 40061c05: 4602e2 l8ui a14, a2, 70 40061c08: 003b addi.n a0, a0, 3 @@ -153058,7 +153060,7 @@ Disassembly of section .text: 40061c38: 20aab0 or a10, a10, a11 40061c3b: 0020c0 memw 40061c3e: 08a9 s32i.n a10, a8, 0 -40061c40: 357247 bbci a2, 20, 40061c79 +40061c40: 357247 bbci a2, 20, 40061c79 <_x_unk_40061b88+0xf1> 40061c43: ffcc21 l32r a2, 40061b74 40061c46: f4afa1 l32r a10, 4005ef04 40061c49: 0020c0 memw @@ -153082,7 +153084,7 @@ Disassembly of section .text: 40061c79: 0020c0 memw 40061c7c: 08a8 l32i.n a10, a8, 0 40061c7e: 000992 l8ui a9, a9, 0 -40061c81: 277277 bbci a2, 23, 40061cac +40061c81: 277277 bbci a2, 23, 40061cac <_x_unk_40061b88+0x124> 40061c84: 993b addi.n a9, a9, 3 40061c86: 00af22 movi a2, 0xffffff00 40061c89: 749090 extui a9, a9, 0, 8 @@ -153096,10 +153098,10 @@ Disassembly of section .text: 40061ca0: 0298 l32i.n a9, a2, 0 40061ca2: 108980 and a8, a9, a8 40061ca5: bba092 movi a9, 187 -40061ca8: 003546 j 40061d81 +40061ca8: 003546 j 40061d81 <_x_unk_40061b88+0x1f9> 40061cab: 997b00 lsi f0, a11, 0x264 40061cae: 749090 extui a9, a9, 0, 8 -40061cb1: 2062e7 bbci a2, 14, 40061cd5 +40061cb1: 2062e7 bbci a2, 14, 40061cd5 <_x_unk_40061b88+0x14d> 40061cb4: 00af22 movi a2, 0xffffff00 40061cb7: 102a20 and a2, a10, a2 40061cba: 202920 or a2, a9, a2 @@ -153111,7 +153113,7 @@ Disassembly of section .text: 40061ccb: 0298 l32i.n a9, a2, 0 40061ccd: 108980 and a8, a9, a8 40061cd0: b93c movi.n a9, 59 -40061cd2: 002ac6 j 40061d81 +40061cd2: 002ac6 j 40061d81 <_x_unk_40061b88+0x1f9> 40061cd5: 00af22 movi a2, 0xffffff00 40061cd8: 102a20 and a2, a10, a2 40061cdb: 202920 or a2, a9, a2 @@ -153123,7 +153125,7 @@ Disassembly of section .text: 40061cec: 0298 l32i.n a9, a2, 0 40061cee: 108980 and a8, a9, a8 40061cf1: b90c movi.n a9, 11 -40061cf3: 002286 j 40061d81 +40061cf3: 002286 j 40061d81 <_x_unk_40061b88+0x1f9> 40061cf6: c00000 sub a0, a0, a0 40061cf9: 280020 lsi f2, a0, 160 40061cfc: a008 l32i.n a0, a0, 40 @@ -153131,14 +153133,14 @@ Disassembly of section .text: 40061d01: a90020 lsi f2, a0, 0x2a4 40061d04: 9208 l32i.n a0, a2, 36 40061d06: 0009 s32i.n a0, a0, 0 -40061d08: 19dc bnez.n a9, 40061d1d +40061d08: 19dc bnez.n a9, 40061d1d <_x_unk_40061b88+0x195> 40061d0a: 0020c0 memw 40061d0d: 0898 l32i.n a9, a8, 0 40061d0f: ff9b21 l32r a2, 40061b7c 40061d12: 102920 and a2, a9, a2 40061d15: 0020c0 memw 40061d18: 0829 s32i.n a2, a8, 0 -40061d1a: 0009c6 j 40061d45 +40061d1a: 0009c6 j 40061d45 <_x_unk_40061b88+0x1bd> 40061d1d: 0020c0 memw 40061d20: 08a8 l32i.n a10, a8, 0 40061d22: ff9721 l32r a2, 40061b80 @@ -153185,7 +153187,7 @@ Disassembly of section .text: 40061d90 : 40061d90: 004136 entry a1, 32 -40061d93: fffe81 l32r a8, 40061d8c +40061d93: fffe81 l32r a8, 40061d8c <_x_unk_40061b88+0x204> 40061d96: 742020 extui a2, a2, 0, 8 40061d99: 000892 l8ui a9, a8, 0 40061d9c: ff7581 l32r a8, 40061b70 @@ -153516,7 +153518,7 @@ Disassembly of section .text: 400620da: 0020c0 memw 400620dd: 0239 s32i.n a3, a2, 0 400620df: f01d retw.n -400620e1: ff2a31 l32r a3, 40061d8c +400620e1: ff2a31 l32r a3, 40061d8c <_x_unk_40061b88+0x204> 400620e4: 180c movi.n a8, 1 400620e6: 004382 s8i a8, a3, 0 400620e9: 543020 extui a3, a2, 0, 6 @@ -153708,17 +153710,19 @@ Disassembly of section .text: 400622b7: 20f800 or a15, a8, a0 400622ba: f83ff4 lsi f15, a15, 0x3e0 400622bd: 3ff430 f64cmph a15, a4, a3, 3 + +400622c0 <_x_unk_spi_400622c0>: 400622c0: 006136 entry a1, 48 400622c3: fffd81 l32r a8, 400622b8 400622c6: 0020c0 memw 400622c9: 002832 l32i a3, a8, 0 400622cc: 243030 extui a3, a3, 0, 3 -400622cf: ff3356 bnez a3, 400622c6 +400622cf: ff3356 bnez a3, 400622c6 <_x_unk_spi_400622c0+0x6> 400622d2: fffa81 l32r a8, 400622bc 400622d5: 0020c0 memw 400622d8: 0838 l32i.n a3, a8, 0 400622da: 243030 extui a3, a3, 0, 3 -400622dd: ff4356 bnez a3, 400622d5 +400622dd: ff4356 bnez a3, 400622d5 <_x_unk_spi_400622c0+0x15> 400622e0: 14c2a2 addi a10, a2, 20 400622e3: 01bd mov.n a11, a1 400622e5: fff865 call8 4006226c @@ -153730,7 +153734,7 @@ Disassembly of section .text: 400622f0 : 400622f0: 004136 entry a1, 32 400622f3: 02ad mov.n a10, a2 -400622f5: fffca5 call8 400622c0 +400622f5: fffca5 call8 400622c0 <_x_unk_spi_400622c0> 400622f8: ffdc81 l32r a8, 40062268 400622fb: 0020c0 memw 400622fe: 0839 s32i.n a3, a8, 0 @@ -153743,7 +153747,7 @@ Disassembly of section .text: 40062310: 0838 l32i.n a3, a8, 0 40062312: ff7356 bnez a3, 4006230d 40062315: 02ad mov.n a10, a2 -40062317: fffaa5 call8 400622c0 +40062317: fffaa5 call8 400622c0 <_x_unk_spi_400622c0> 4006231a: 032d mov.n a2, a3 4006231c: f01d retw.n ... @@ -153753,7 +153757,7 @@ Disassembly of section .text: 40062323: 030c movi.n a3, 0 40062325: 02ad mov.n a10, a2 40062327: 006132 s32i a3, a1, 0 -4006232a: fff965 call8 400622c0 +4006232a: fff965 call8 400622c0 <_x_unk_spi_400622c0> 4006232d: ff9f81 l32r a8, 400621ac 40062330: 68f431 l32r a3, 4003c700 40062333: 0020c0 memw @@ -153787,7 +153791,7 @@ Disassembly of section .text: 4006237a: 02b897 bgeu a8, a9, 40062380 4006237d: 002f46 j 4006243e 40062380: 02ad mov.n a10, a2 -40062382: fff3e5 call8 400622c0 +40062382: fff3e5 call8 400622c0 <_x_unk_spi_400622c0> 40062385: f61c movi.n a6, 31 40062387: 002986 j 40062431 4006238a: 910000 srl a0, a0 @@ -153851,7 +153855,7 @@ Disassembly of section .text: 40062427: 0898 l32i.n a9, a8, 0 40062429: ff7956 bnez a9, 40062424 4006242c: 02ad mov.n a10, a2 -4006242e: ffe925 call8 400622c0 +4006242e: ffe925 call8 400622c0 <_x_unk_spi_400622c0> 40062431: 0215a6 blti a5, 1, 40062437 40062434: ffd506 j 4006238c 40062437: 060c movi.n a6, 0 @@ -153865,7 +153869,7 @@ Disassembly of section .text: 40062448 : 40062448: 004136 entry a1, 32 4006244b: fffea1 l32r a10, 40062444 -4006244e: ffe725 call8 400622c0 +4006244e: ffe725 call8 400622c0 <_x_unk_spi_400622c0> 40062451: 02ad mov.n a10, a2 40062453: 5b3c movi.n a11, 53 40062455: ffd5a5 call8 400621b0 @@ -153930,7 +153934,7 @@ Disassembly of section .text: 400624eb: 01b9 s32i.n a11, a1, 0 400624ed: 2189 s32i.n a8, a1, 8 400624ef: 31c9 s32i.n a12, a1, 12 -400624f1: ffdce5 call8 400622c0 +400624f1: ffdce5 call8 400622c0 <_x_unk_spi_400622c0> 400624f4: ff2691 l32r a9, 4006218c 400624f7: ff28d1 l32r a13, 40062198 400624fa: 0020c0 memw @@ -154456,7 +154460,7 @@ Disassembly of section .text: 40062a2e: 205450 or a5, a4, a5 40062a31: 0020c0 memw 40062a34: 0259 s32i.n a5, a2, 0 -40062a36: ff1525 call8 40061b88 +40062a36: ff1525 call8 40061b88 <_x_unk_40061b88> 40062a39: 020c movi.n a2, 0 40062a3b: f01d retw.n 40062a3d: 000000 ill @@ -154542,7 +154546,7 @@ Disassembly of section .text: 40062b11: 0020c0 memw 40062b14: 0899 s32i.n a9, a8, 0 40062b16: 00a0a2 movi a10, 0 -40062b19: ff06e5 call8 40061b88 +40062b19: ff06e5 call8 40061b88 <_x_unk_40061b88> 40062b1c: ffd081 l32r a8, 40062a5c 40062b1f: 390c movi.n a9, 3 40062b21: 0020c0 memw @@ -154575,7 +154579,7 @@ Disassembly of section .text: 40062b64 : 40062b64: 004136 entry a1, 32 40062b67: fe37a1 l32r a10, 40062444 -40062b6a: ff7565 call8 400622c0 +40062b6a: ff7565 call8 400622c0 <_x_unk_spi_400622c0> 40062b6d: fd8781 l32r a8, 4006218c 40062b70: ff71a1 l32r a10, 40062934 40062b73: 0020c0 memw @@ -154605,7 +154609,7 @@ Disassembly of section .text: 40062bb2: 208a80 or a8, a10, a8 40062bb5: 0020c0 memw 40062bb8: 0289 s32i.n a8, a2, 0 -40062bba: fefce5 call8 40061b88 +40062bba: fefce5 call8 40061b88 <_x_unk_40061b88> 40062bbd: 020c movi.n a2, 0 40062bbf: f01d retw.n 40062bc1: 000000 ill @@ -154617,7 +154621,7 @@ Disassembly of section .text: 40062bcb: fe1ea1 l32r a10, 40062444 40062bce: 742020 extui a2, a2, 0, 8 40062bd1: 743030 extui a3, a3, 0, 8 -40062bd4: ff6ea5 call8 400622c0 +40062bd4: ff6ea5 call8 400622c0 <_x_unk_spi_400622c0> 40062bd7: 1322f6 bgeui a2, 2, 40062bee 40062bda: fffa21 l32r a2, 40062bc4 40062bdd: c03230 sub a3, a2, a3 @@ -154651,7 +154655,7 @@ Disassembly of section .text: 40062c22: 120c movi.n a2, 1 40062c24: 01ea56 bnez a10, 40062c46 40062c27: 03ad mov.n a10, a3 -40062c29: ff6965 call8 400622c0 +40062c29: ff6965 call8 400622c0 <_x_unk_spi_400622c0> 40062c2c: cd6581 l32r a8, 400561c0 40062c2f: fd5f21 l32r a2, 400621ac 40062c32: 0020c0 memw @@ -154661,7 +154665,7 @@ Disassembly of section .text: 40062c3c: 0828 l32i.n a2, a8, 0 40062c3e: ff7256 bnez a2, 40062c39 40062c41: 03ad mov.n a10, a3 -40062c43: ff67e5 call8 400622c0 +40062c43: ff67e5 call8 400622c0 <_x_unk_spi_400622c0> 40062c46: f01d retw.n 40062c48: 800000 add a0, a0, a0 ... @@ -154697,7 +154701,7 @@ Disassembly of section .text: 40062c94: 022382 l32i a8, a3, 8 40062c97: 20a330 or a10, a3, a3 40062c9a: 822280 mull a2, a2, a8 -40062c9d: ff6225 call8 400622c0 +40062c9d: ff6225 call8 400622c0 <_x_unk_spi_400622c0> 40062ca0: 786c81 l32r a8, 40040e50 40062ca3: 102280 and a2, a2, a8 40062ca6: fdac81 l32r a8, 40062358 @@ -154712,7 +154716,7 @@ Disassembly of section .text: 40062cbf: 0828 l32i.n a2, a8, 0 40062cc1: ff7256 bnez a2, 40062cbc 40062cc4: 03ad mov.n a10, a3 -40062cc6: ff5fa5 call8 400622c0 +40062cc6: ff5fa5 call8 400622c0 <_x_unk_spi_400622c0> 40062cc9: f01d retw.n ... @@ -154750,7 +154754,7 @@ Disassembly of section .text: 40062d1b: b48040 extui a8, a4, 0, 12 40062d1e: b8ec bnez.n a8, 40062d4d 40062d20: 03ad mov.n a10, a3 -40062d22: ff59e5 call8 400622c0 +40062d22: ff59e5 call8 400622c0 <_x_unk_spi_400622c0> 40062d25: 784a21 l32r a2, 40040e50 40062d28: 104420 and a4, a4, a2 40062d2b: fd8b21 l32r a2, 40062358 @@ -154765,7 +154769,7 @@ Disassembly of section .text: 40062d43: 0428 l32i.n a2, a4, 0 40062d45: ff7256 bnez a2, 40062d40 40062d48: 03ad mov.n a10, a3 -40062d4a: ff5765 call8 400622c0 +40062d4a: ff5765 call8 400622c0 <_x_unk_spi_400622c0> 40062d4d: f01d retw.n ... @@ -155148,7 +155152,7 @@ Disassembly of section .text: 400630e2: 150c movi.n a5, 1 400630e4: 02b867 bgeu a8, a6, 400630ea 400630e7: 002e86 j 400631a5 -400630ea: ff1d65 call8 400622c0 +400630ea: ff1d65 call8 400622c0 <_x_unk_spi_400622c0> 400630ed: fd3c movi.n a13, 63 400630ef: fc2b91 l32r a9, 4006219c 400630f2: fc99a1 l32r a10, 40062358 @@ -159680,7 +159684,7 @@ Disassembly of section .text: 40067043: 0afd82 s32ri a8, a13, 40 40067046: ff .byte 0xff 40067047: 8800f4 lsi f15, a0, 0x220 -4006704a: eb43a1 l32r a10, 40061d58 +4006704a: eb43a1 l32r a10, 40061d58 <_x_unk_40061b88+0x1d0> 4006704d: 7cbf20 lsi f2, a15, 0x1f0 40067050: 3090f6 bgeui a0, 10, 40067084 <__udivmoddi4+0x25d4> 40067053: a80eb0 lsi f11, a14, 0x2a0 @@ -163392,7 +163396,7 @@ Disassembly of section .text: 400695e4: d10c movi.n a1, 13 400695e6: c12d lsi f2, a1, 4 400695e8: 4e .byte 0x4e -400695e9: e16ff1 l32r a15, 40061ba8 +400695e9: e16ff1 l32r a15, 40061ba8 <_x_unk_40061b88+0x20> 400695ec: a11080 lsi f8, a0, 0x284 400695ef: 30c200 xor a12, a2, a0 400695f2: 0420e3 lsi f14, a0, 16 @@ -164326,7 +164330,7 @@ Disassembly of section .text: 40069e64: bc0074 lsi f7, a0, 0x2f0 40069e67: 30e2a3 lsi f10, a2, 192 40069e6a: d4bb addi.n a13, a4, 11 -40069e6c: dfa541 l32r a4, 40061d00 +40069e6c: dfa541 l32r a4, 40061d00 <_x_unk_40061b88+0x178> 40069e6f: d74a add.n a13, a7, a4 40069e71: 3dd895 call4 400a7bfc <__bss_start+0x37bfc> 40069e74: c46d lsi f6, a4, 16 diff --git a/common/platforms/esp32/rom/rom.S b/common/platforms/esp32/rom/rom.S index 0d10642..11bd296 100644 --- a/common/platforms/esp32/rom/rom.S +++ b/common/platforms/esp32/rom/rom.S @@ -9,6 +9,8 @@ here = . #include "rom_functions.S" +PROVIDE ( _x_unk_40061b88, 0x40061b88 ) +PROVIDE ( _x_unk_spi_400622c0, 0x400622c0 ) PROVIDE ( _c_3ff000c8, 0x40062df0 ) PROVIDE ( _c_3ff5b024, 0x40062e0c ) PROVIDE ( _c_3ff5b000, 0x40062e10 ) diff --git a/common/platforms/esp32/rom/rom.elf b/common/platforms/esp32/rom/rom.elf index 160613057b6feccdc9df29d8860c4cefa4933764..f65fbf09996b1f49996ff815c7e28fdabe12fd06 100755 GIT binary patch delta 391 zcmezJMt;Xz`3VY)3mO$$6&YIk=z ziGK&kk3-`B0rD9b*d4&`Wng4rYyh*sd;uVz1I&lWgZLt7d}RF~c?Nx+lH3CQRiuFnr@uhj$@g@caW`;=?77XzaesMu2Sj@;M*2Lk|^vOfC& delta 364 zcmdn-R{qNy`3VY)F^!6?ij1v_Os$H{t%@wIima`QY+DuC(@W|<=(0I5fB_?eRXqa( zj~;^W2ILDM@q>VT5hQ*bkS~G6&jRu%Ao0t9d=n)8bRa(jiNB+sp`IZQN#F)h0RscO z1K2$bj0|_dd1 diff --git a/common/platforms/esp32/stubs/Makefile b/common/platforms/esp32/stubs/Makefile index 0c21588..857512a 100644 --- a/common/platforms/esp32/stubs/Makefile +++ b/common/platforms/esp32/stubs/Makefile @@ -28,6 +28,7 @@ $(STUB_ELF): $(STUB) $(LIBS) -mtext-section-literals -mlongcalls -nostdlib -fno-builtin \ -I. -I/src/common/platforms/esp \ -I/opt/Espressif/esp-idf/components/esp32/include \ + -I/opt/Espressif/esp-idf/components/soc/esp32/include \ -L/opt/Espressif/esp-idf -Wl,-static \ -ffunction-sections -Wl,--gc-sections \ -Tstub.ld -o $@ $^" diff --git a/common/platforms/esp32/stubs/sdkconfig.h b/common/platforms/esp32/stubs/sdkconfig.h new file mode 100644 index 0000000..0ecac13 --- /dev/null +++ b/common/platforms/esp32/stubs/sdkconfig.h @@ -0,0 +1 @@ +#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 diff --git a/common/platforms/esp32/stubs/spi_flash.c b/common/platforms/esp32/stubs/spi_flash.c deleted file mode 100644 index 697c410..0000000 --- a/common/platforms/esp32/stubs/spi_flash.c +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* - * SPI magic required to get the flash chip into writable state. - * Replaces stock ROM's SPIUnlock. - * - * Cargo-culted from - * https://github.com/espressif/esptool/blob/5c6962e894e0a118c9a4b5760876433493449260/flasher_stub/stub_write_flash.c - */ - -#include "rom/spi_flash.h" -#include "soc/spi_reg.h" - -static SpiFlashChip *flashchip = (SpiFlashChip *) 0x3ffae270; - -#define STATUS_WIP_BIT (1 << 0) /* Write in Progress */ -#define STATUS_QIE_BIT (1 << 9) /* Quad Enable */ - -#define SPI_IDX 1 - -/* - * Wait for the SPI state machine to be ready, - * ie no command in progress in the internal host. - */ -static void spi_wait_ready(void) { - while (REG_READ(SPI_EXT2_REG(SPI_IDX)) & SPI_ST) { - } - while (REG_READ(SPI_EXT2_REG(0)) & SPI_ST) { - } -} - -/* - * Returns true if the spiflash is ready for its next write operation. - * Doesn't block, except for the SPI state machine to finish - * any previous SPI host operation. - */ -static bool spiflash_is_ready(void) { - spi_wait_ready(); - REG_WRITE(SPI_RD_STATUS_REG(SPI_IDX), 0); - /* Issue read status command */ - REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_RDSR); - while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { - } - uint32_t status_value = REG_READ(SPI_RD_STATUS_REG(SPI_IDX)); - return (status_value & STATUS_WIP_BIT) == 0; -} - -static void spiflash_wait_ready(void) { - while (!spiflash_is_ready()) { - } -} - -static void spi_write_enable(void) { - spiflash_wait_ready(); - REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); - while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { - } -} - -/* - * Stub version of SPIUnlock() that replaces version in ROM. - * This works around a bug where SPIUnlock sometimes reads the wrong - * high status byte (RDSR2 result) and then copies it back to the - * flash status, causing lock bit CMP or Status Register Protect ` to - * become set. - */ -SpiFlashOpResult SPIUnlock(void) { - uint32_t status; - - spi_wait_ready(); - - if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } - - /* - * Clear all bits except QIE, if it is set. - * (This is different from ROM SPIUnlock, which keeps all bits as-is.) - */ - status &= STATUS_QIE_BIT; - - spi_write_enable(); - - SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); - if (SPI_write_status(flashchip, status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } - - return SPI_FLASH_RESULT_OK; -} diff --git a/common/platforms/esp32/stubs/stub.ld b/common/platforms/esp32/stubs/stub.ld index a53321c..663b4e0 100644 --- a/common/platforms/esp32/stubs/stub.ld +++ b/common/platforms/esp32/stubs/stub.ld @@ -40,3 +40,6 @@ SECTIONS { } INCLUDE "components/esp32/ld/esp32.rom.ld" + +PROVIDE(esp_rom_spiflash_attach = 0x40062a6c); +PROVIDE(esp_rom_spiflash_config_clk = 0x40062bc8); diff --git a/common/platforms/esp8266/stubs/rom_functions.h b/common/platforms/esp8266/stubs/rom_functions.h index f156c66..8922207 100644 --- a/common/platforms/esp8266/stubs/rom_functions.h +++ b/common/platforms/esp8266/stubs/rom_functions.h @@ -28,6 +28,15 @@ uint32_t SPI_read_status(); uint32_t Wait_SPI_Idle(); void spi_flash_attach(); +/* ESP32 API compatibility */ +#define esp_rom_spiflash_unlock SPIUnlock +#define esp_rom_spiflash_erase_sector SPIEraseSector +#define esp_rom_spiflash_erase_block SPIEraseBlock +#define esp_rom_spiflash_erase_chip SPIEraseChip +#define esp_rom_spiflash_read SPIRead +#define esp_rom_spiflash_write SPIWrite +#define esp_rom_spiflash_config_param SPIParamCfg + void SelectSpiFunction(); void SPIFlashModeConfig(uint32_t a, uint32_t b); void SPIReadModeCnfig(uint32_t a); From d5b2ea4212371451091d5838b71c6395e38494db Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 2 Jun 2017 12:21:31 +0100 Subject: [PATCH 011/265] Flasher: LED debugging aids + minor optimization PUBLISHED_FROM=f7b10ce6fe7aa6d2cc631bd6ffff210ada168099 --- common/platforms/esp/stub_flasher.c | 29 +++++++++++++++++++++++------ common/platforms/esp32/stubs/led.c | 26 ++++++++++++++++++++++++++ common/platforms/esp32/stubs/led.h | 11 +++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 common/platforms/esp32/stubs/led.c create mode 100644 common/platforms/esp32/stubs/led.h diff --git a/common/platforms/esp/stub_flasher.c b/common/platforms/esp/stub_flasher.c index c0c5c12..2034066 100644 --- a/common/platforms/esp/stub_flasher.c +++ b/common/platforms/esp/stub_flasher.c @@ -29,6 +29,7 @@ #include "ets_sys.h" #elif defined(ESP32) #include "soc/uart_reg.h" +#include "led.h" #endif #include "slip.h" @@ -89,7 +90,7 @@ int do_flash_erase(uint32_t addr, uint32_t len) { struct uart_buf { uint8_t data[UART_BUF_SIZE]; uint32_t nr; - uint8_t *pr, *pw; + uint8_t *pr, *pw, *pe; }; uint32_t ccount(void) { @@ -115,16 +116,21 @@ static struct uart_buf ub; void uart_isr(void *arg) { uint32_t int_st = READ_PERI_REG(UART_INT_ST_REG(0)); - uint8_t fifo_len; + uint8_t fifo_len, nr, i; + // led_on(22); while ((fifo_len = READ_PERI_REG(UART_STATUS_REG(0))) > 0 && ub.nr < UART_BUF_SIZE) { - while (fifo_len-- > 0 && ub.nr < UART_BUF_SIZE) { + nr = fifo_len; + if (ub.nr + nr > UART_BUF_SIZE) nr = UART_BUF_SIZE - ub.nr; + if (nr > ub.pe - ub.pw) nr = ub.pe - ub.pw; + for (i = 0; i < nr; i++) { uint8_t byte = READ_PERI_REG(UART_FIFO_REG(0)); *ub.pw++ = byte; - ub.nr++; - if (ub.pw >= ub.data + UART_BUF_SIZE) ub.pw = ub.data; } + if (ub.pw == ub.pe) ub.pw = ub.data; + ub.nr += nr; } + // led_off(22); WRITE_PERI_REG(UART_INT_CLR_REG(0), int_st); (void) arg; } @@ -140,6 +146,7 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { ub.nr = 0; ub.pr = ub.pw = ub.data; + ub.pe = ub.data + UART_BUF_SIZE; ets_isr_attach(ETS_UART0_INUM, uart_isr, &ub); uint32_t saved_conf1 = READ_PERI_REG(UART_CONF1_REG(0)); /* Reduce frequency of UART interrupts */ @@ -176,14 +183,20 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { start_count = ccount(); /* Wait for data to arrive. */ wp.buf_level = *nr; + // led_on(16); while (*nr < FLASH_WRITE_SIZE) { } + // led_off(16); wr.wait_time += ccount() - start_count; MD5Update(&ctx, ub.pr, FLASH_WRITE_SIZE); + // led_on(2); start_count = ccount(); - if (esp_rom_spiflash_write(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != 0) + if (esp_rom_spiflash_write(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != + 0) { return 0x37; + } wr.write_time += ccount() - start_count; + // led_off(2); ets_intr_lock(); *nr -= FLASH_WRITE_SIZE; ets_intr_unlock(); @@ -375,6 +388,10 @@ void stub_main(void) { SLIP_send(&greeting, 4); + // led_setup(22); + // led_setup(16); + // led_setup(2); + last_cmd = cmd_loop(); ets_delay_us(10000); diff --git a/common/platforms/esp32/stubs/led.c b/common/platforms/esp32/stubs/led.c new file mode 100644 index 0000000..ffe566f --- /dev/null +++ b/common/platforms/esp32/stubs/led.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014-2017 Cesanta Software Limited + * All rights reserved + */ + +#include "soc/gpio_reg.h" + +void led_setup(int io) { + WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, 1 << io); +} + +void led_on(int io) { + WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io); +} + +void led_off(int io) { + WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io); +} + +void led_toggle(int io) { + if (READ_PERI_REG(GPIO_OUT_REG & 1 << io)) { + WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io); + } else { + WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io); + } +} diff --git a/common/platforms/esp32/stubs/led.h b/common/platforms/esp32/stubs/led.h new file mode 100644 index 0000000..505a3f6 --- /dev/null +++ b/common/platforms/esp32/stubs/led.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2014-2017 Cesanta Software Limited + * All rights reserved + */ + +#pragma once + +void led_setup(int io); +void led_on(int io); +void led_off(int io); +void led_toggle(int io); From 71ad378546033ccb2fedd083896252d86af3f12b Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 3 Jun 2017 11:28:58 +0100 Subject: [PATCH 012/265] Add -j and -f opts for mjs cli PUBLISHED_FROM=7f3ee7b34a261a74102c61f082b8b0fb9cb4ab26 --- mjs.c | 12 ++++++++---- mjs/src/mjs_main.c | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/mjs.c b/mjs.c index dca1425..c8ea56f 100644 --- a/mjs.c +++ b/mjs.c @@ -10217,13 +10217,17 @@ int main(int argc, char *argv[]) { struct mjs *mjs = mjs_create(); mjs_val_t res = MJS_UNDEFINED; mjs_err_t err = MJS_OK; - int i; + int i, generate_jsc = 0; - for (i = 1; i < argc && argv[i][0] == '-'; i++) { + for (i = 1; i < argc && argv[i][0] == '-' && err == MJS_OK; i++) { if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { cs_log_set_level(atoi(argv[++i])); + } else if (strcmp(argv[i], "-j") == 0) { + generate_jsc = 1; } else if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) { err = mjs_exec(mjs, argv[++i], &res); + } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) { + err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); printf("Usage:\n "); @@ -10234,8 +10238,8 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } } - for (; i < argc; i++) { - err = mjs_exec_file(mjs, argv[i], 1, &res); + for (; i < argc && err == MJS_OK; i++) { + err = mjs_exec_file(mjs, argv[i], generate_jsc, &res); } if (err == MJS_OK) { diff --git a/mjs/src/mjs_main.c b/mjs/src/mjs_main.c index a0e4ed8..c5dfd4c 100644 --- a/mjs/src/mjs_main.c +++ b/mjs/src/mjs_main.c @@ -17,13 +17,17 @@ int main(int argc, char *argv[]) { struct mjs *mjs = mjs_create(); mjs_val_t res = MJS_UNDEFINED; mjs_err_t err = MJS_OK; - int i; + int i, generate_jsc = 0; - for (i = 1; i < argc && argv[i][0] == '-'; i++) { + for (i = 1; i < argc && argv[i][0] == '-' && err == MJS_OK; i++) { if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { cs_log_set_level(atoi(argv[++i])); + } else if (strcmp(argv[i], "-j") == 0) { + generate_jsc = 1; } else if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) { err = mjs_exec(mjs, argv[++i], &res); + } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) { + err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); printf("Usage:\n "); @@ -34,8 +38,8 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } } - for (; i < argc; i++) { - err = mjs_exec_file(mjs, argv[i], 1, &res); + for (; i < argc && err == MJS_OK; i++) { + err = mjs_exec_file(mjs, argv[i], generate_jsc, &res); } if (err == MJS_OK) { From 07a8bf3fe31f6f75bcf59a8b7ab0360c79ba5088 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 3 Jun 2017 11:45:25 +0100 Subject: [PATCH 013/265] Squash build warnings on Mac PUBLISHED_FROM=b691b89bc58021281687c79f5144ea8c08cce8cf --- mjs.c | 4 ++-- mjs/src/mjs_exec.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index c8ea56f..eb0609a 100644 --- a/mjs.c +++ b/mjs.c @@ -7799,7 +7799,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { bp = *mjs_bcode_part_get_by_offset(mjs, off_ret); code = (const uint8_t *) bp.data.p; i = off_ret - bp.start_idx; - LOG(LL_VERBOSE_DEBUG, ("RETURNING TO %d", off_ret + 1)); + LOG(LL_VERBOSE_DEBUG, ("RETURNING TO %d", (int) off_ret + 1)); } else { goto clean; } @@ -8122,7 +8122,7 @@ mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, int i; size_t addr = mjs_get_func_addr(func); - LOG(LL_VERBOSE_DEBUG, ("applying func %d", mjs_get_func_addr(func))); + LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); mjs_val_t prev_this_val = mjs->vals.this_obj; diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 75cba30..e55f527 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -706,7 +706,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { bp = *mjs_bcode_part_get_by_offset(mjs, off_ret); code = (const uint8_t *) bp.data.p; i = off_ret - bp.start_idx; - LOG(LL_VERBOSE_DEBUG, ("RETURNING TO %d", off_ret + 1)); + LOG(LL_VERBOSE_DEBUG, ("RETURNING TO %d", (int) off_ret + 1)); } else { goto clean; } @@ -1029,7 +1029,7 @@ mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, int i; size_t addr = mjs_get_func_addr(func); - LOG(LL_VERBOSE_DEBUG, ("applying func %d", mjs_get_func_addr(func))); + LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); mjs_val_t prev_this_val = mjs->vals.this_obj; From b9625b32f9b09071faeee4babb662b86498cc7ea Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 3 Jun 2017 11:50:37 +0100 Subject: [PATCH 014/265] Enable dlsym on Mac cli PUBLISHED_FROM=ce2fcd10b91a689cc888662e3077534993ed7bda --- mjs/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mjs/Makefile b/mjs/Makefile index dc3620e..0d018cc 100644 --- a/mjs/Makefile +++ b/mjs/Makefile @@ -35,6 +35,10 @@ ifeq ($(UNAME_S),Linux) ASAN_CFLAGS += -fsanitize=leak endif +ifeq ($(UNAME_S),Darwin) + MFLAGS += -D_DARWIN_C_SOURCE +endif + PROG = $(BUILD_DIR)/mjs all: $(PROG) From 303d60f9213873826ccfc8e4f212c540885307c2 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 3 Jun 2017 11:54:29 +0100 Subject: [PATCH 015/265] Update usage string PUBLISHED_FROM=dd3cdf912434612423d7f56a08b3964b00315114 --- mjs.c | 9 +++++++-- mjs/src/mjs_main.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index eb0609a..75f64cd 100644 --- a/mjs.c +++ b/mjs.c @@ -10230,8 +10230,13 @@ int main(int argc, char *argv[]) { err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); - printf("Usage:\n "); - printf("%s [-l debug_level] [-e expression] js_file ...\n", argv[0]); + printf("Usage:\n"); + printf("%s [OPTIONS] [js_file ...]\n", argv[0]); + printf("OPTIONS:\n"); + printf(" -e string - Execute JavaScript expression\n"); + printf(" -j - Enable code precompiling to .jsc files\n"); + printf(" -f js_file - Execute code from .js JavaScript file\n"); + printf(" -l level - Set debug level, from 0 to 5\n"); return EXIT_SUCCESS; } else { fprintf(stderr, "Unknown flag: [%s]\n", argv[i]); diff --git a/mjs/src/mjs_main.c b/mjs/src/mjs_main.c index c5dfd4c..30d980b 100644 --- a/mjs/src/mjs_main.c +++ b/mjs/src/mjs_main.c @@ -30,8 +30,13 @@ int main(int argc, char *argv[]) { err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); - printf("Usage:\n "); - printf("%s [-l debug_level] [-e expression] js_file ...\n", argv[0]); + printf("Usage:\n"); + printf("%s [OPTIONS] [js_file ...]\n", argv[0]); + printf("OPTIONS:\n"); + printf(" -e string - Execute JavaScript expression\n"); + printf(" -j - Enable code precompiling to .jsc files\n"); + printf(" -f js_file - Execute code from .js JavaScript file\n"); + printf(" -l level - Set debug level, from 0 to 5\n"); return EXIT_SUCCESS; } else { fprintf(stderr, "Unknown flag: [%s]\n", argv[i]); From 3f53e04d2ff06f82868d8181287e380740b2f278 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 3 Jun 2017 23:35:13 +0300 Subject: [PATCH 016/265] Unescape JSON.parse()-d strings PUBLISHED_FROM=83865fe6ecff20a93025527deab3ea2ddc39bbe7 --- mjs.c | 16 ++++++++++++++-- mjs/src/mjs_json.c | 16 ++++++++++++++-- mjs/tests/test_11.js | 5 +++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/mjs.c b/mjs.c index 75f64cd..c650e03 100644 --- a/mjs.c +++ b/mjs.c @@ -10054,9 +10054,21 @@ static void frozen_cb(void *data, const char *name, size_t name_len, mjs_own(ctx->mjs, &v); switch (token->type) { - case JSON_TYPE_STRING: - v = mjs_mk_string(ctx->mjs, token->ptr, token->len, 1 /* copy */); + case JSON_TYPE_STRING: { + char *dst; + if (token->len > 0 && (dst = malloc(token->len)) != NULL) { + int len = json_unescape(token->ptr, token->len, dst, token->len); + v = mjs_mk_string(ctx->mjs, dst, len, 1 /* copy */); + free(dst); + } else { + /* + * This branch is for 0-len strings, and for malloc errors + * TODO(lsm): on malloc error, propagate the error upstream + */ + v = mjs_mk_string(ctx->mjs, "", 0, 1 /* copy */); + } break; + } case JSON_TYPE_NUMBER: v = mjs_mk_number(ctx->mjs, strtod(token->ptr, NULL)); break; diff --git a/mjs/src/mjs_json.c b/mjs/src/mjs_json.c index f1ab2b2..e118e59 100644 --- a/mjs/src/mjs_json.c +++ b/mjs/src/mjs_json.c @@ -336,9 +336,21 @@ static void frozen_cb(void *data, const char *name, size_t name_len, mjs_own(ctx->mjs, &v); switch (token->type) { - case JSON_TYPE_STRING: - v = mjs_mk_string(ctx->mjs, token->ptr, token->len, 1 /* copy */); + case JSON_TYPE_STRING: { + char *dst; + if (token->len > 0 && (dst = malloc(token->len)) != NULL) { + int len = json_unescape(token->ptr, token->len, dst, token->len); + v = mjs_mk_string(ctx->mjs, dst, len, 1 /* copy */); + free(dst); + } else { + /* + * This branch is for 0-len strings, and for malloc errors + * TODO(lsm): on malloc error, propagate the error upstream + */ + v = mjs_mk_string(ctx->mjs, "", 0, 1 /* copy */); + } break; + } case JSON_TYPE_NUMBER: v = mjs_mk_number(ctx->mjs, strtod(token->ptr, NULL)); break; diff --git a/mjs/tests/test_11.js b/mjs/tests/test_11.js index b9bc1bf..c516dbd 100644 --- a/mjs/tests/test_11.js +++ b/mjs/tests/test_11.js @@ -1,4 +1,5 @@ -let s = '{"a": 1, "b": "foo", "c": true, "d": [null]}'; +let s = '{"a": 1, "b": "foo", "c": true, "d": [null], "e": "1\\n2"}'; let o = JSON.parse(s); +let z = JSON.parse('""'); // Zero-length string let s2 = JSON.stringify(o); -s2 === '{"d":[null],"c":true,"b":"foo","a":1}' && o.c && o.a === 1; +s2 === '{"e":"1\\n2","d":[null],"c":true,"b":"foo","a":1}' && o.c && o.a === 1 && o.e === '1\n2' && z === ''; From 1228d43a195ac911406471aa3d2962e00c1cbc77 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 6 Jun 2017 00:48:45 +0300 Subject: [PATCH 017/265] Fix mmapping .jsc file if it is up to date PUBLISHED_FROM=dd9e4154aa7848d3e0706954f0526cd75571970c --- mjs.c | 20 ++++++++++++++------ mjs/src/mjs_exec.c | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/mjs.c b/mjs.c index c650e03..180add7 100644 --- a/mjs.c +++ b/mjs.c @@ -8011,6 +8011,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, if (basename_len > 0 && strcmp(path + basename_len, jsext) == 0) { /* source file has a .js extension: create a .jsc counterpart */ int rewrite = 1; + int read_mmapped = 1; /* construct .jsc filename */ const char *jscext = ".jsc"; @@ -8050,17 +8051,24 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, /* write last bcode part to .jsc */ fwrite(bp->data.p, bp->data.len, 1, fp); fclose(fp); + } else { + LOG(LL_WARN, ("Failed to open %s for writing", filename_jsc)); + read_mmapped = 0; + } + } - /* free RAM buffer with last bcode part */ - free((void *) bp->data.p); + if (read_mmapped) { + /* free RAM buffer with last bcode part */ + free((void *) bp->data.p); - /* mmap .jsc file and set last bcode part buffer to it */ - bp->data.p = cs_mmap_file(filename_jsc, &bp->data.len); - bp->in_rom = 1; - } + /* mmap .jsc file and set last bcode part buffer to it */ + bp->data.p = cs_mmap_file(filename_jsc, &bp->data.len); + bp->in_rom = 1; } } } +#else + (void) generate_jsc; #endif mjs_execute(mjs, off, &r); diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index e55f527..c480502 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -918,6 +918,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, if (basename_len > 0 && strcmp(path + basename_len, jsext) == 0) { /* source file has a .js extension: create a .jsc counterpart */ int rewrite = 1; + int read_mmapped = 1; /* construct .jsc filename */ const char *jscext = ".jsc"; @@ -957,17 +958,24 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, /* write last bcode part to .jsc */ fwrite(bp->data.p, bp->data.len, 1, fp); fclose(fp); + } else { + LOG(LL_WARN, ("Failed to open %s for writing", filename_jsc)); + read_mmapped = 0; + } + } - /* free RAM buffer with last bcode part */ - free((void *) bp->data.p); + if (read_mmapped) { + /* free RAM buffer with last bcode part */ + free((void *) bp->data.p); - /* mmap .jsc file and set last bcode part buffer to it */ - bp->data.p = cs_mmap_file(filename_jsc, &bp->data.len); - bp->in_rom = 1; - } + /* mmap .jsc file and set last bcode part buffer to it */ + bp->data.p = cs_mmap_file(filename_jsc, &bp->data.len); + bp->in_rom = 1; } } } +#else + (void) generate_jsc; #endif mjs_execute(mjs, off, &r); From 88b387b60595f57db0fb6b6b94b682dac666865d Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 6 Jun 2017 12:56:17 +0100 Subject: [PATCH 018/265] Add mjs.generate_jsc config value PUBLISHED_FROM=a4ca585215eb562e89b55abb44e575ccfb06111c --- mjs.c | 40 ++++++++++++++++++++++----------------- mjs.h | 28 ++++++++++++++++++--------- mjs/src/mjs_builtin.c | 2 +- mjs/src/mjs_core.c | 4 ++++ mjs/src/mjs_core.h | 1 + mjs/src/mjs_core_public.h | 9 +++++++++ mjs/src/mjs_exec.c | 6 +++--- mjs/src/mjs_exec_public.h | 10 +--------- mjs/src/mjs_main.c | 8 ++++---- mjs/tests/unit_test.c | 2 +- 10 files changed, 66 insertions(+), 44 deletions(-) diff --git a/mjs.c b/mjs.c index 180add7..3a54a9a 100644 --- a/mjs.c +++ b/mjs.c @@ -2170,6 +2170,15 @@ void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg, */ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); +/* + * Sets whether *.jsc files are generated when *.js file is executed. By + * default it's 0. + * + * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no + * effect. + */ +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -2686,6 +2695,7 @@ struct mjs { unsigned inhibit_gc : 1; unsigned need_gc : 1; + unsigned generate_jsc : 1; }; /* @@ -3710,15 +3720,7 @@ extern "C" { mjs_err_t mjs_exec(struct mjs *, const char *src, mjs_val_t *res); mjs_err_t mjs_exec_buf(struct mjs *, const char *src, size_t, mjs_val_t *res); -/* - * Execute file. If `generate_jsc` is non-zero, and the filename ends with - * ".js", the ".jsc" file will be generated. - * - * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then `generate_jsc` has no - * effect. - */ -mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, - mjs_val_t *res); +mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res); mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args); mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, @@ -6468,7 +6470,7 @@ static void mjs_load(struct mjs *mjs) { bp = mjs_get_loaded_file_bcode(mjs, path); if (bp == NULL) { /* File was not loaded before, so, load */ - ret = mjs_exec_file(mjs, path, 1, &res); + ret = mjs_exec_file(mjs, path, &res); } else { /* * File was already loaded before, so if it was evaluated successfully, @@ -6999,6 +7001,10 @@ MJS_PRIVATE mjs_val_t mjs_pop_val(struct mbuf *m) { MJS_PRIVATE void mjs_push(struct mjs *mjs, mjs_val_t v) { push_mjs_val(&mjs->stack, v); } + +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc) { + mjs->generate_jsc = generate_jsc; +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_dataview.c" #endif @@ -8003,6 +8009,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, mjs_val_t r = MJS_UNDEFINED; mjs->error = mjs_parse(path, src, mjs); if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1, stderr); + if (generate_jsc == -1) generate_jsc = mjs->generate_jsc; if (mjs->error == MJS_OK) { #if MJS_GENERATE_JSC && defined(CS_MMAP) if (generate_jsc && path != NULL) { @@ -8081,8 +8088,7 @@ mjs_err_t mjs_exec(struct mjs *mjs, const char *src, mjs_val_t *res) { return mjs_exec_internal(mjs, "", src, 0 /* generate_jsc */, res); } -mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, - mjs_val_t *res) { +mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res) { mjs_err_t error = MJS_FILE_READ_ERROR; mjs_val_t r = MJS_UNDEFINED; size_t size; @@ -8095,7 +8101,7 @@ mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, } r = MJS_UNDEFINED; - error = mjs_exec_internal(mjs, path, source_code, generate_jsc, &r); + error = mjs_exec_internal(mjs, path, source_code, -1, &r); free(source_code); clean: @@ -10237,17 +10243,17 @@ int main(int argc, char *argv[]) { struct mjs *mjs = mjs_create(); mjs_val_t res = MJS_UNDEFINED; mjs_err_t err = MJS_OK; - int i, generate_jsc = 0; + int i; for (i = 1; i < argc && argv[i][0] == '-' && err == MJS_OK; i++) { if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { cs_log_set_level(atoi(argv[++i])); } else if (strcmp(argv[i], "-j") == 0) { - generate_jsc = 1; + mjs_set_generate_jsc(mjs, 1); } else if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) { err = mjs_exec(mjs, argv[++i], &res); } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) { - err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); + err = mjs_exec_file(mjs, argv[++i], &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); printf("Usage:\n"); @@ -10264,7 +10270,7 @@ int main(int argc, char *argv[]) { } } for (; i < argc && err == MJS_OK; i++) { - err = mjs_exec_file(mjs, argv[i], generate_jsc, &res); + err = mjs_exec_file(mjs, argv[i], &res); } if (err == MJS_OK) { diff --git a/mjs.h b/mjs.h index 4542cbe..88db6e7 100644 --- a/mjs.h +++ b/mjs.h @@ -253,6 +253,15 @@ void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg, */ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); +/* + * Sets whether *.jsc files are generated when *.js file is executed. By + * default it's 0. + * + * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no + * effect. + */ +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -509,6 +518,15 @@ void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg, */ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); +/* + * Sets whether *.jsc files are generated when *.js file is executed. By + * default it's 0. + * + * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no + * effect. + */ +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -535,15 +553,7 @@ extern "C" { mjs_err_t mjs_exec(struct mjs *, const char *src, mjs_val_t *res); mjs_err_t mjs_exec_buf(struct mjs *, const char *src, size_t, mjs_val_t *res); -/* - * Execute file. If `generate_jsc` is non-zero, and the filename ends with - * ".js", the ".jsc" file will be generated. - * - * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then `generate_jsc` has no - * effect. - */ -mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, - mjs_val_t *res); +mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res); mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args); mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index 7e4cc93..d0906c6 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -68,7 +68,7 @@ static void mjs_load(struct mjs *mjs) { bp = mjs_get_loaded_file_bcode(mjs, path); if (bp == NULL) { /* File was not loaded before, so, load */ - ret = mjs_exec_file(mjs, path, 1, &res); + ret = mjs_exec_file(mjs, path, &res); } else { /* * File was already loaded before, so if it was evaluated successfully, diff --git a/mjs/src/mjs_core.c b/mjs/src/mjs_core.c index 98b546b..d0ab01d 100644 --- a/mjs/src/mjs_core.c +++ b/mjs/src/mjs_core.c @@ -377,3 +377,7 @@ MJS_PRIVATE mjs_val_t mjs_pop_val(struct mbuf *m) { MJS_PRIVATE void mjs_push(struct mjs *mjs, mjs_val_t v) { push_mjs_val(&mjs->stack, v); } + +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc) { + mjs->generate_jsc = generate_jsc; +} diff --git a/mjs/src/mjs_core.h b/mjs/src/mjs_core.h index 2d07813..3aea4d3 100644 --- a/mjs/src/mjs_core.h +++ b/mjs/src/mjs_core.h @@ -134,6 +134,7 @@ struct mjs { unsigned inhibit_gc : 1; unsigned need_gc : 1; + unsigned generate_jsc : 1; }; /* diff --git a/mjs/src/mjs_core_public.h b/mjs/src/mjs_core_public.h index f96782e..c964107 100644 --- a/mjs/src/mjs_core_public.h +++ b/mjs/src/mjs_core_public.h @@ -194,6 +194,15 @@ void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg, */ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); +/* + * Sets whether *.jsc files are generated when *.js file is executed. By + * default it's 0. + * + * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no + * effect. + */ +void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index c480502..b524b8e 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -910,6 +910,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, mjs_val_t r = MJS_UNDEFINED; mjs->error = mjs_parse(path, src, mjs); if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1, stderr); + if (generate_jsc == -1) generate_jsc = mjs->generate_jsc; if (mjs->error == MJS_OK) { #if MJS_GENERATE_JSC && defined(CS_MMAP) if (generate_jsc && path != NULL) { @@ -988,8 +989,7 @@ mjs_err_t mjs_exec(struct mjs *mjs, const char *src, mjs_val_t *res) { return mjs_exec_internal(mjs, "", src, 0 /* generate_jsc */, res); } -mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, - mjs_val_t *res) { +mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res) { mjs_err_t error = MJS_FILE_READ_ERROR; mjs_val_t r = MJS_UNDEFINED; size_t size; @@ -1002,7 +1002,7 @@ mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, } r = MJS_UNDEFINED; - error = mjs_exec_internal(mjs, path, source_code, generate_jsc, &r); + error = mjs_exec_internal(mjs, path, source_code, -1, &r); free(source_code); clean: diff --git a/mjs/src/mjs_exec_public.h b/mjs/src/mjs_exec_public.h index 159a222..2ce8fc0 100644 --- a/mjs/src/mjs_exec_public.h +++ b/mjs/src/mjs_exec_public.h @@ -16,15 +16,7 @@ extern "C" { mjs_err_t mjs_exec(struct mjs *, const char *src, mjs_val_t *res); mjs_err_t mjs_exec_buf(struct mjs *, const char *src, size_t, mjs_val_t *res); -/* - * Execute file. If `generate_jsc` is non-zero, and the filename ends with - * ".js", the ".jsc" file will be generated. - * - * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then `generate_jsc` has no - * effect. - */ -mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, int generate_jsc, - mjs_val_t *res); +mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res); mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args); mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, diff --git a/mjs/src/mjs_main.c b/mjs/src/mjs_main.c index 30d980b..1d8af4a 100644 --- a/mjs/src/mjs_main.c +++ b/mjs/src/mjs_main.c @@ -17,17 +17,17 @@ int main(int argc, char *argv[]) { struct mjs *mjs = mjs_create(); mjs_val_t res = MJS_UNDEFINED; mjs_err_t err = MJS_OK; - int i, generate_jsc = 0; + int i; for (i = 1; i < argc && argv[i][0] == '-' && err == MJS_OK; i++) { if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { cs_log_set_level(atoi(argv[++i])); } else if (strcmp(argv[i], "-j") == 0) { - generate_jsc = 1; + mjs_set_generate_jsc(mjs, 1); } else if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) { err = mjs_exec(mjs, argv[++i], &res); } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) { - err = mjs_exec_file(mjs, argv[++i], generate_jsc, &res); + err = mjs_exec_file(mjs, argv[++i], &res); } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("mJS (c) Cesanta, built: " __DATE__ "\n"); printf("Usage:\n"); @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { } } for (; i < argc && err == MJS_OK; i++) { - err = mjs_exec_file(mjs, argv[i], generate_jsc, &res); + err = mjs_exec_file(mjs, argv[i], &res); } if (err == MJS_OK) { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index b2e0be2..44b9c97 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -233,7 +233,7 @@ const char *test_exec(void) { mjs = mjs_create(); mjs_own(mjs, &res); - ASSERT_EXEC_OK(mjs_exec_file(mjs, path, 1, &res)); + ASSERT_EXEC_OK(mjs_exec_file(mjs, path, &res)); ASSERT_EQ(mjs_get_bool(mjs, res), 1); mjs_disown(mjs, &res); ASSERT_EQ(mjs->owned_values.len, 0); From f2af6bfddfc475ff43e097e3d8ebbf8338e2a4af Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 12 Jun 2017 21:17:54 +0300 Subject: [PATCH 019/265] Add test for passing JS bufs to C PUBLISHED_FROM=aee64a9596e932a6f396dd9d3874175bc584abd8 --- mjs/tests/unit_test.c | 47 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 44b9c97..72e2d81 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -731,6 +731,15 @@ void ffi_test_cb_viiiiiu(cb_viiiiiu *cb, void *userdata) { } /* }}} */ +static void ffi_test_inbuf(char *buf, int len) { + char pattern[] = { 'a', 'b', 0, 'c', 'd', 1 }; + int i; + for (i = 0; i < len; i++) { + buf[i] = pattern[i % sizeof(pattern)]; + } +} + + void *stub_dlsym(void *handle, const char *name) { (void) handle; if (strcmp(name, "ffi_get_null") == 0) return ffi_get_null; @@ -750,6 +759,7 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "ffi_test_cb_iiui") == 0) return ffi_test_cb_iiui; if (strcmp(name, "ffi_test_cb_iiui2") == 0) return ffi_test_cb_iiui2; if (strcmp(name, "ffi_test_cb_viiiiiu") == 0) return ffi_test_cb_viiiiiu; + if (strcmp(name, "ffi_test_inbuf") == 0) return ffi_test_inbuf; if (strcmp(name, "malloc") == 0) return malloc; if (strcmp(name, "calloc") == 0) return calloc; if (strcmp(name, "free") == 0) return free; @@ -1002,6 +1012,41 @@ const char *test_call_ffi(struct mjs *mjs) { ASSERT_EQ(mjs_exec(mjs, "ffi_test_s1s('\\x01')", &res), MJS_TYPE_ERROR); ASSERT_STREQ(mjs->error_msg, "failed to call FFIed function: non-ffi-callable value"); + /* Test the ability to pass char buffers to C */ + { + size_t len; + const char *p, *result = "\x61\x62\x00\x63\x64\x01\x61\x62\x00\x63"; + + /* Try big string, big read */ + ASSERT_EQ(mjs_exec(mjs, "let buf = 'o1o2o3o4o5'; ", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "let f = ffi('void ffi_test_inbuf(char *, int)');", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "f(buf, buf.length);", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "buf", &res), MJS_OK); + p = mjs_get_string(mjs, &res, &len); + ASSERT(p != NULL); + ASSERT_EQ(len, 10); + ASSERT_EQ(memcmp(p, result, len), 0); + + /* Try big string, small read */ + ASSERT_EQ(mjs_exec(mjs, "buf = 'o1o2o3o4o5';", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "f(buf, 2);", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "buf", &res), MJS_OK); + p = mjs_get_string(mjs, &res, &len); + ASSERT(p != NULL); + ASSERT_EQ(len, 10); + ASSERT_STREQ(p, "abo2o3o4o5"); + + /* Try small string, small read */ + ASSERT_EQ(mjs_exec(mjs, "buf = 'o1';", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "f(buf, buf.length);", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "buf", &res), MJS_OK); + p = mjs_get_string(mjs, &res, &len); + ASSERT(p != NULL); + ASSERT_EQ(len, 2); + /* TODO(lsm): enable */ + /* ASSERT_STREQ(p, "ab"); */ + } + mjs_disown(mjs, &res); return NULL; @@ -3210,7 +3255,6 @@ const char *test_lib_math(struct mjs *mjs) { static const char *run_all_tests(const char *filter, double *total_elapsed) { cs_log_set_level(2); - RUN_TEST(test_exec); RUN_TEST_MJS(test_arithmetic); RUN_TEST_MJS(test_block); @@ -3257,6 +3301,7 @@ static const char *run_all_tests(const char *filter, double *total_elapsed) { RUN_TEST_MJS(test_dataview); RUN_TEST_MJS(test_lib_math); + RUN_TEST(test_exec); return NULL; } From 755cb13ff0bddc43acc0e62c46995f85f5c026e9 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 13 Jun 2017 02:16:44 +0300 Subject: [PATCH 020/265] Add file doc PUBLISHED_FROM=9e0c5c4c841d7d72093cdbe5c4e83bf8cf89a8a1 --- mjs/lib/api_file.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mjs/lib/api_file.js b/mjs/lib/api_file.js index 38d68c5..42b91ac 100644 --- a/mjs/lib/api_file.js +++ b/mjs/lib/api_file.js @@ -1,7 +1,10 @@ let File = { - // **`File.read(name)`** - read the whole file into a string variable. + // **`File.read(name)`** + // Read the whole file into a string variable. + // // Return value: a string contents of the file. // If file does not exist, an empty string is returned. + // // Example: read a .json configuration file into a config object: // ```javascript // let obj = JSON.parse(File.read('settings.json')); @@ -17,15 +20,19 @@ let File = { return res; }, - // **`File.remove(name)`** - delete file with a given name. Return value: 0 + // **`File.remove(name)`** + // Delete file with a given name. Return value: 0 // on success, non-0 on failure. remove: ffi('int remove(char *)'), - // **`File.write(str, name, mode)`** - write string `str` into file `name`. + // **`File.write(str, name, mode)`** + // Write string `str` into file `name`. + // // If file does not exist, it is created. `mode` is an optional file open // mode argument, `'w'` by default, which means that previous content is // deleted. Set `mode` to `'a'` in order to append to the existing content. // Return value: number of bytes written. + // // Example - write a configuration object into a file: // ```javascript // File.write(JSON.stringify(obj, 'settings.json')); From a7a6f3c6e3372f12ad1a2a77f9db9aaa506ea326 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 13 Jun 2017 16:22:43 +0100 Subject: [PATCH 021/265] mOS filesystem refactoring: introduce VFS With different filesystem implementations and storage drivers, like grown-ups have :) This is not currently used to add any new functionality, we still have only one FS and driver on ESP8266 and ESP32; CC3200 has two: SPIFFS and SLFS. This will be used soon to implement filesystems on additional SPI flash chips and SD cards. PUBLISHED_FROM=293960fef82952c505e9b1925aac7724c7308362 --- common/cs_file.c | 4 +- common/platforms/esp/src/esp_mmap.c | 8 +++- common/platforms/platform_cc3200.h | 2 +- common/platforms/platform_esp8266.h | 2 + common/platforms/simplelink/sl_fs.c | 51 +++++++++++++----------- common/platforms/simplelink/sl_fs_slfs.c | 18 ++++----- common/platforms/simplelink/sl_ssl_if.c | 17 ++++++-- mjs.c | 8 ++-- 8 files changed, 65 insertions(+), 45 deletions(-) diff --git a/common/cs_file.c b/common/cs_file.c index 9828867..8c3a18f 100644 --- a/common/cs_file.c +++ b/common/cs_file.c @@ -43,9 +43,9 @@ char *cs_read_file(const char *path, size_t *size) { char *cs_mmap_file(const char *path, size_t *size) WEAK; char *cs_mmap_file(const char *path, size_t *size) { char *r; - int fd = open(path, O_RDONLY); + int fd = open(path, O_RDONLY, 0); struct stat st; - if (fd == -1) return NULL; + if (fd < 0) return NULL; fstat(fd, &st); *size = (size_t) st.st_size; r = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); diff --git a/common/platforms/esp/src/esp_mmap.c b/common/platforms/esp/src/esp_mmap.c index b44e1ec..157e4eb 100644 --- a/common/platforms/esp/src/esp_mmap.c +++ b/common/platforms/esp/src/esp_mmap.c @@ -31,6 +31,11 @@ #ifdef CS_MMAP +#define SPIFFS_PAGE_HEADER_SIZE (sizeof(spiffs_page_header)) +/* XXX: This should really be taken from a particular fs */ +#define LOG_PAGE_SIZE 256 +#define SPIFFS_PAGE_DATA_SIZE ((LOG_PAGE_SIZE) - (SPIFFS_PAGE_HEADER_SIZE)) + #define MMAP_DESCS_ADD_SIZE 4 #define MMAP_ADDR_MASK ((1 << MMAP_ADDR_BITS) - 1) @@ -247,11 +252,10 @@ void esp_spiffs_on_page_move_hook(spiffs *fs, spiffs_file fh, } int esp_spiffs_dummy_read(spiffs *fs, u32_t addr, u32_t size, u8_t *dst) { - (void) fs; (void) size; if (dst >= DUMMY_MMAP_BUFFER_START && dst < DUMMY_MMAP_BUFFER_END) { - if ((addr - SPIFFS_PAGE_HEADER_SIZE) % LOG_PAGE_SIZE == 0) { + if ((addr - SPIFFS_PAGE_HEADER_SIZE) % SPIFFS_CFG_LOG_PAGE_SZ(fs) == 0) { addr &= MMAP_ADDR_MASK; cur_mmap_desc->blocks[cur_mmap_desc->pages++] = FLASH_BASE(fs) + addr; } diff --git a/common/platforms/platform_cc3200.h b/common/platforms/platform_cc3200.h index 24de764..b7ec878 100644 --- a/common/platforms/platform_cc3200.h +++ b/common/platforms/platform_cc3200.h @@ -76,7 +76,7 @@ struct stat { }; int _stat(const char *pathname, struct stat *st); -#define stat(a, b) _stat(a, b) +int stat(const char *pathname, struct stat *st); #define __S_IFMT 0170000 diff --git a/common/platforms/platform_esp8266.h b/common/platforms/platform_esp8266.h index 8dd4e66..1c84807 100644 --- a/common/platforms/platform_esp8266.h +++ b/common/platforms/platform_esp8266.h @@ -19,7 +19,9 @@ #define SIZE_T_FMT "u" typedef struct stat cs_stat_t; #define DIRSEP '/' +#if !defined(MGOS_VFS_DEFINE_DIRENT) #define CS_DEFINE_DIRENT +#endif #define to64(x) strtoll(x, NULL, 10) #define INT64_FMT PRId64 diff --git a/common/platforms/simplelink/sl_fs.c b/common/platforms/simplelink/sl_fs.c index 59d828b..fc09342 100644 --- a/common/platforms/simplelink/sl_fs.c +++ b/common/platforms/simplelink/sl_fs.c @@ -6,6 +6,32 @@ #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \ (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS)) +int set_errno(int e) { + errno = e; + return (e == 0 ? 0 : -1); +} + +const char *drop_dir(const char *fname, bool *is_slfs) { + if (is_slfs != NULL) { + *is_slfs = (strncmp(fname, "SL:", 3) == 0); + if (*is_slfs) fname += 3; + } + /* Drop "./", if any */ + if (fname[0] == '.' && fname[1] == '/') { + fname += 2; + } + /* + * Drop / if it is the only one in the path. + * This allows use of /pretend/directories but serves /file.txt as normal. + */ + if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) { + fname++; + } + return fname; +} + +#if !defined(MG_FS_NO_VFS) + #include #include #include @@ -43,30 +69,6 @@ #endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* !MG_UART_CHAR_PUT */ -int set_errno(int e) { - errno = e; - return (e == 0 ? 0 : -1); -} - -static const char *drop_dir(const char *fname, bool *is_slfs) { - if (is_slfs != NULL) { - *is_slfs = (strncmp(fname, "SL:", 3) == 0); - if (*is_slfs) fname += 3; - } - /* Drop "./", if any */ - if (fname[0] == '.' && fname[1] == '/') { - fname += 2; - } - /* - * Drop / if it is the only one in the path. - * This allows use of /pretend/directories but serves /file.txt as normal. - */ - if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) { - fname++; - } - return fname; -} - enum fd_type { FD_INVALID, FD_SYS, @@ -404,5 +406,6 @@ int sl_fs_init(void) { return ret; } +#endif /* !defined(MG_FS_NO_VFS) */ #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \ defined(MG_FS_SPIFFS)) */ diff --git a/common/platforms/simplelink/sl_fs_slfs.c b/common/platforms/simplelink/sl_fs_slfs.c index 9290307..b338887 100644 --- a/common/platforms/simplelink/sl_fs_slfs.c +++ b/common/platforms/simplelink/sl_fs_slfs.c @@ -21,8 +21,8 @@ #include "common/mg_mem.h" /* From sl_fs.c */ -extern int set_errno(int e); -static const char *drop_dir(const char *fname, bool *is_slfs); +int set_errno(int e); +const char *drop_dir(const char *fname, bool *is_slfs); /* * With SLFS, you have to pre-declare max file size. Yes. Really. @@ -85,6 +85,7 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { _u32 am = 0; fi->size = (size_t) -1; int rw = (flags & 3); + size_t new_size = FS_SLFS_MAX_FILE_SIZE; if (rw == O_RDONLY) { SlFsFileInfo_t sl_fi; _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); @@ -99,25 +100,24 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { return set_errno(ENOTSUP); } if (flags & O_CREAT) { - size_t i, size = FS_SLFS_MAX_FILE_SIZE; + size_t i; for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { if (s_sl_file_size_hints[i].name != NULL && strcmp(s_sl_file_size_hints[i].name, pathname) == 0) { - size = s_sl_file_size_hints[i].size; + new_size = s_sl_file_size_hints[i].size; MG_FREE(s_sl_file_size_hints[i].name); s_sl_file_size_hints[i].name = NULL; break; } } - DBG(("creating %s with max size %d", pathname, (int) size)); - am = FS_MODE_OPEN_CREATE(size, 0); + am = FS_MODE_OPEN_CREATE(new_size, 0); } else { am = FS_MODE_OPEN_WRITE; } } _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh); - DBG(("sl_FsOpen(%s, 0x%x) = %d, %d", pathname, (int) am, (int) r, - (int) fi->fh)); + LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d, %d", pathname, (int) am, + (unsigned int) new_size, (int) r, (int) fi->fh)); if (r == SL_FS_OK) { fi->pos = 0; r = fd; @@ -132,7 +132,7 @@ int fs_slfs_close(int fd) { struct sl_fd_info *fi = &s_sl_fds[fd]; if (fi->fh <= 0) return set_errno(EBADF); _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0); - DBG(("sl_FsClose(%d) = %d", (int) fi->fh, (int) r)); + LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r)); s_sl_fds[fd].fh = -1; return set_errno(sl_fs_to_errno(r)); } diff --git a/common/platforms/simplelink/sl_ssl_if.c b/common/platforms/simplelink/sl_ssl_if.c index 24c96e8..95c801d 100644 --- a/common/platforms/simplelink/sl_ssl_if.c +++ b/common/platforms/simplelink/sl_ssl_if.c @@ -7,6 +7,13 @@ #include "common/mg_mem.h" +#ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX +#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:" +#endif + +#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \ + (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1) + struct mg_ssl_if_ctx { char *ssl_cert; char *ssl_key; @@ -71,7 +78,8 @@ bool pem_to_der(const char *pem_file, const char *der_file) { pf = fopen(pem_file, "r"); if (pf == NULL) goto clean; remove(der_file); - fs_slfs_set_new_file_size(der_file + 3, 2048); + fs_slfs_set_new_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, + 2048); df = fopen(der_file, "w"); if (df == NULL) goto clean; while (1) { @@ -113,8 +121,8 @@ static char *sl_pem2der(const char *pem_file) { } char *der_file = NULL; /* DER file must be located on SLFS, add prefix. */ - int l = mg_asprintf(&der_file, 0, "SL:%.*s.der", (int) (pem_ext - pem_file), - pem_file); + int l = mg_asprintf(&der_file, 0, MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "%.*s.der", + (int) (pem_ext - pem_file), pem_file); if (der_file == NULL) return NULL; bool result = false; cs_stat_t st; @@ -127,7 +135,8 @@ static char *sl_pem2der(const char *pem_file) { } if (result) { /* Strip the SL: prefix we added since NWP does not expect it. */ - memmove(der_file, der_file + 3, l - 2 /* including \0 */); + memmove(der_file, der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, + l - 2 /* including \0 */); } else { MG_FREE(der_file); der_file = NULL; diff --git a/mjs.c b/mjs.c index 3a54a9a..9c5b604 100644 --- a/mjs.c +++ b/mjs.c @@ -506,7 +506,9 @@ typedef struct stat cs_stat_t; #define SIZE_T_FMT "u" typedef struct stat cs_stat_t; #define DIRSEP '/' +#if !defined(MGOS_VFS_DEFINE_DIRENT) #define CS_DEFINE_DIRENT +#endif #define to64(x) strtoll(x, NULL, 10) #define INT64_FMT PRId64 @@ -726,7 +728,7 @@ struct stat { }; int _stat(const char *pathname, struct stat *st); -#define stat(a, b) _stat(a, b) +int stat(const char *pathname, struct stat *st); #define __S_IFMT 0170000 @@ -4198,9 +4200,9 @@ char *cs_read_file(const char *path, size_t *size) { char *cs_mmap_file(const char *path, size_t *size) WEAK; char *cs_mmap_file(const char *path, size_t *size) { char *r; - int fd = open(path, O_RDONLY); + int fd = open(path, O_RDONLY, 0); struct stat st; - if (fd == -1) return NULL; + if (fd < 0) return NULL; fstat(fd, &st); *size = (size_t) st.st_size; r = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); From f687c85cb66976d75c9ee9bf80a01c837d525364 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Wed, 14 Jun 2017 14:58:00 +0300 Subject: [PATCH 022/265] Add at alias to charCodeAt, and document PUBLISHED_FROM=e2f6c77ea3f2fdffae95a3cac433cb7c2036bcd9 --- README.md | 4 ++++ mjs.c | 2 +- mjs/src/mjs_exec.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b093a6a..3973bfe 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,10 @@ where it enables scripting for IoT devices.
Return a substring between two indices. Example: 'abcdef'.slice(1,3) === 'bc';
+
'abc'.at(0);
+
Return numeric byte value at given string index. Example: + 'abc'.at(0) === 0x61;
+
let a = [1,2,3,4,5]; a.splice(start, deleteCount, ...);
Change the contents of an array by removing existing elements and/or adding new elements. Example: diff --git a/mjs.c b/mjs.c index 9c5b604..c6ab16f 100644 --- a/mjs.c +++ b/mjs.c @@ -7500,7 +7500,7 @@ static int getprop_builtin_string(struct mjs *mjs, mjs_val_t val, } else if (strcmp(name, "slice") == 0) { *res = mjs_mk_foreign(mjs, mjs_string_slice); return 1; - } else if (strcmp(name, "charCodeAt") == 0) { + } else if (strcmp(name, "at") == 0 || strcmp(name, "charCodeAt") == 0) { *res = mjs_mk_foreign(mjs, mjs_string_char_code_at); return 1; } else if (isnum) { diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index b524b8e..f7765e9 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -399,7 +399,7 @@ static int getprop_builtin_string(struct mjs *mjs, mjs_val_t val, } else if (strcmp(name, "slice") == 0) { *res = mjs_mk_foreign(mjs, mjs_string_slice); return 1; - } else if (strcmp(name, "charCodeAt") == 0) { + } else if (strcmp(name, "at") == 0 || strcmp(name, "charCodeAt") == 0) { *res = mjs_mk_foreign(mjs, mjs_string_char_code_at); return 1; } else if (isnum) { From 3d95860ae5d2416d8802d8cfdb13490bd282c2f0 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 14 Jun 2017 17:21:59 +0100 Subject: [PATCH 023/265] Add tests for at() PUBLISHED_FROM=3525b4e42508bcf282198ca402d52c6e17376250 --- mjs/tests/unit_test.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 72e2d81..a2e68e0 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2535,15 +2535,27 @@ const char *test_string(struct mjs *mjs) { ASSERT_EXEC_OK(mjs_exec(mjs, "'abcdef'.charCodeAt(0)", &res)); ASSERT_EQ(mjs_get_int(mjs, res), 'a'); + ASSERT_EXEC_OK(mjs_exec(mjs, "'abcdef'.at(0)", &res)); + ASSERT_EQ(mjs_get_int(mjs, res), 'a'); + ASSERT_EXEC_OK(mjs_exec(mjs, "'abcdef'.charCodeAt(-1)", &res)); ASSERT_EQ(mjs_get_int(mjs, res), 'f'); + ASSERT_EXEC_OK(mjs_exec(mjs, "'abcdef'.at(-1)", &res)); + ASSERT_EQ(mjs_get_int(mjs, res), 'f'); + ASSERT_EXEC_OK(mjs_exec(mjs, "'\\xff'.charCodeAt(0)", &res)); ASSERT_EQ(mjs_get_int(mjs, res), 255); + ASSERT_EXEC_OK(mjs_exec(mjs, "'\\xff'.at(0)", &res)); + ASSERT_EQ(mjs_get_int(mjs, res), 255); + ASSERT_EXEC_OK(mjs_exec(mjs, "'\\xff'.charCodeAt(1)", &res)); ASSERT_EQ(res, MJS_UNDEFINED); + ASSERT_EXEC_OK(mjs_exec(mjs, "'\\xff'.at(1)", &res)); + ASSERT_EQ(res, MJS_UNDEFINED); + /* concatenation */ ASSERT_EXEC_OK(mjs_exec(mjs, "'foo' + 'bar' === 'foobar'", &res)); From 94e1feb13374ed86ab3707131143ae9e779a88a9 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 14 Jun 2017 22:24:48 +0100 Subject: [PATCH 024/265] Autoformat apps and libs PUBLISHED_FROM=73532022e1c6feb77216d3ca0371be935a4e1768 --- common.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common.mk b/common.mk index acdafec..957363c 100644 --- a/common.mk +++ b/common.mk @@ -10,6 +10,13 @@ GO_PACKAGES = $(shell go list cesanta.com/cloud/... | grep -v vendor) \ FORMAT_FILES ?= '*.[ch]' REPO_ABS_PATH := $(shell cd $(REPO_ROOT) && pwd) +# Additional filter shell command for files to format; it could be for example +# "grep -v foobar", or even "grep -v foo | grep -v bar" (without quotes). +FORMAT_FILES_FILTER_CMD ?= +ifneq ("$(FORMAT_FILES_FILTER_CMD)","") + FORMAT_FILES_FILTER_CMD += | +endif + CLANG = clang ifneq ("$(wildcard /usr/bin/clang-3.6)","") CLANG:=/usr/bin/clang-3.6 @@ -33,5 +40,6 @@ format: @test -d "$(REPO_ROOT)" && true || { echo "Define REPO_ROOT Makefile variable, REPO_ROOT/common.mk wants it." ; false ; } @git --git-dir $(REPO_ABS_PATH)/.git --work-tree $(REPO_ROOT) \ ls-files --full-name $(FORMAT_FILES) | \ + $(FORMAT_FILES_FILTER_CMD) \ xargs -IFILE echo $(REPO_ABS_PATH)/FILE | \ xargs -t $(CLANG_FORMAT) -i From b3099a6764b7ad8d48702ce089a07d18e7df39d3 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 15 Jun 2017 23:35:42 +0100 Subject: [PATCH 025/265] Implement Math.random() Also provide Math.rand(), for good measure. PUBLISHED_FROM=bdd60e511eb97ef3295a2cefff9b33758b32d545 --- mjs/lib/api_math.js | 2 ++ mjs/tests/unit_test.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mjs/lib/api_math.js b/mjs/lib/api_math.js index 8fd559d..66d815d 100644 --- a/mjs/lib/api_math.js +++ b/mjs/lib/api_math.js @@ -11,4 +11,6 @@ let Math = { pow: ffi('double pow(double, double)'), sin: ffi('double sin(double)'), cos: ffi('double cos(double)'), + rand: ffi('int rand()'), + random: function() { return Math.rand() / 0x7fffffff; }, }; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index a2e68e0..ec59135 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -1,4 +1,5 @@ #include +#include #include "mjs.h" #if defined(__cplusplus) @@ -770,6 +771,7 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "mjs_mem_get_int") == 0) return mjs_mem_get_int; if (strcmp(name, "ceil") == 0) return ceil; if (strcmp(name, "floor") == 0) return floor; + if (strcmp(name, "rand") == 0) return rand; if (strcmp(name, "round") == 0) return round; if (strcmp(name, "fmax") == 0) return fmax; if (strcmp(name, "fmin") == 0) return fmin; From 6756ee2225fa66aac03afa53cae0b86c3bfc6385 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 19 Jun 2017 13:34:27 +0100 Subject: [PATCH 026/265] Add gc() root level func PUBLISHED_FROM=7e4389b0645a3d59af60a6092176c988b1a0a653 --- README.md | 3 +++ mjs.c | 7 +++++++ mjs/src/mjs_builtin.c | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 3973bfe..1492dcf 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,9 @@ where it enables scripting for IoT devices.
let f = ffi('int foo(int)');
Import C function into mJS. See next section.
+ +
gc(full);
+
Perform garbage collection. If `full` is `true`, reclaim RAM to OS.
# C/C++ interoperability diff --git a/mjs.c b/mjs.c index c6ab16f..fbef028 100644 --- a/mjs.c +++ b/mjs.c @@ -6510,6 +6510,12 @@ static void mjs_get_mjs(struct mjs *mjs) { mjs_return(mjs, mjs_mk_foreign(mjs, mjs)); } +static void mjs_do_gc(struct mjs *mjs) { + mjs_val_t arg0 = mjs_arg(mjs, 0); + mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0); + mjs_return(mjs, arg0); +} + void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_val_t v; @@ -6522,6 +6528,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "fstr", ~0, mjs_mk_foreign(mjs, mjs_fstr)); mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); + mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); /* * Populate JSON.parse() and JSON.stringify() diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index d0906c6..20974c5 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -106,6 +106,12 @@ static void mjs_get_mjs(struct mjs *mjs) { mjs_return(mjs, mjs_mk_foreign(mjs, mjs)); } +static void mjs_do_gc(struct mjs *mjs) { + mjs_val_t arg0 = mjs_arg(mjs, 0); + mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0); + mjs_return(mjs, arg0); +} + void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_val_t v; @@ -118,6 +124,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "fstr", ~0, mjs_mk_foreign(mjs, mjs_fstr)); mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); + mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); /* * Populate JSON.parse() and JSON.stringify() From a496549766f9a7c97e39c96c79bbd2ad58c9636c Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 20 Jun 2017 12:28:20 +0100 Subject: [PATCH 027/265] Return null for NULL value of char pointer PUBLISHED_FROM=24509885ad63ab88c03370e7e26d3a817ccda3b5 --- mjs.c | 6 +++++- mjs/src/mjs_ffi.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index fbef028..421d011 100644 --- a/mjs.c +++ b/mjs.c @@ -8961,7 +8961,11 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { switch (rtype) { case MJS_FFI_CTYPE_CHAR_PTR: { const char *s = (const char *) (uintptr_t) res.v.i; - resv = mjs_mk_string(mjs, s, ~0, 1); + if (s != NULL) { + resv = mjs_mk_string(mjs, s, ~0, 1); + } else { + resv = MJS_NULL; + } break; } case MJS_FFI_CTYPE_VOID_PTR: diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index 52cb6b1..8494684 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -773,7 +773,11 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { switch (rtype) { case MJS_FFI_CTYPE_CHAR_PTR: { const char *s = (const char *) (uintptr_t) res.v.i; - resv = mjs_mk_string(mjs, s, ~0, 1); + if (s != NULL) { + resv = mjs_mk_string(mjs, s, ~0, 1); + } else { + resv = MJS_NULL; + } break; } case MJS_FFI_CTYPE_VOID_PTR: From aff76865ffd020795c7a64a8e947678b6ca09a69 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 19:25:43 +0100 Subject: [PATCH 028/265] Invoke tcp_accepted() on the listening pcb As required by the LWIP API PUBLISHED_FROM=7bfc6d816aa69f8fdd7592ade48b2d52e2d4991a --- common/platforms/lwip/mg_lwip_net_if.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 681a343..5319b45 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -385,15 +385,27 @@ void mg_lwip_handle_accept(struct mg_connection *nc) { } static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { - struct mg_connection *lc = (struct mg_connection *) arg; - DBG(("%p conn %p from %s:%u", lc, newtpcb, + struct mg_connection *lc = (struct mg_connection *) arg, *nc; + struct mg_lwip_conn_state *lcs, *cs; + struct tcp_pcb_listen *lpcb; + LOG(LL_INFO, + ("%p conn %p from %s:%u", lc, newtpcb, IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port)); - struct mg_connection *nc = mg_if_accept_new_conn(lc); + if (lc == NULL) { + tcp_abort(newtpcb); + return ERR_ABRT; + } + lcs = (struct mg_lwip_conn_state *) lc->sock; + lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp; +#if TCP_LISTEN_BACKLOG + tcp_accepted(lpcb); +#endif + nc = mg_if_accept_new_conn(lc); if (nc == NULL) { tcp_abort(newtpcb); return ERR_ABRT; } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + cs = (struct mg_lwip_conn_state *) nc->sock; cs->lc = lc; cs->pcb.tcp = newtpcb; /* We need to set up callbacks before returning because data may start @@ -407,6 +419,7 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { #endif mg_lwip_post_signal(MG_SIG_ACCEPT, nc); (void) err; + (void) lpcb; return ERR_OK; } From 334f2fa6bebd8451c96dcb7ed70a8f2fd8ea0ba1 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 20 Jun 2017 19:38:01 +0100 Subject: [PATCH 029/265] Fix frozen PUBLISHED_FROM=a6a33a2f627e135a419865652b40ecf808a12be8 --- frozen/frozen.c | 19 ++++++++++++------- mjs.c | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 39c0f2f..dcd77e4 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -117,12 +117,11 @@ struct fstate { static int append_to_path(struct frozen *f, const char *str, int size) { int n = f->path_len; - f->path_len += - snprintf(f->path + f->path_len, sizeof(f->path) - (f->path_len), "%.*s", size, str); - if (f->path_len > sizeof(f->path) - 1) { - f->path_len = sizeof(f->path) - 1; - } - + int left = sizeof(f->path) - n - 1; + if (size > left) size = left; + memcpy(f->path + n, str, size); + f->path[n + size] = '\0'; + f->path_len += size; return n; } @@ -859,6 +858,7 @@ static void json_scanf_cb(void *callback_data, const char *name, size_t name_len, const char *path, const struct json_token *token) { struct json_scanf_info *info = (struct json_scanf_info *) callback_data; + char buf[32]; /* Must be enough to hold numbers */ (void) name; (void) name_len; @@ -944,7 +944,12 @@ static void json_scanf_cb(void *callback_data, const char *name, *(struct json_token *) info->target = *token; break; default: - info->num_conversions += sscanf(token->ptr, info->fmt, info->target); + /* Before scanf, copy into tmp buffer in order to 0-terminate it */ + if (token->len < (int) sizeof(buf)) { + memcpy(buf, token->ptr, token->len); + buf[token->len] = '\0'; + info->num_conversions += sscanf(buf, info->fmt, info->target); + } break; } } diff --git a/mjs.c b/mjs.c index 421d011..577ab2d 100644 --- a/mjs.c +++ b/mjs.c @@ -4908,12 +4908,11 @@ struct fstate { static int append_to_path(struct frozen *f, const char *str, int size) { int n = f->path_len; - f->path_len += - snprintf(f->path + f->path_len, sizeof(f->path) - (f->path_len), "%.*s", size, str); - if (f->path_len > sizeof(f->path) - 1) { - f->path_len = sizeof(f->path) - 1; - } - + int left = sizeof(f->path) - n - 1; + if (size > left) size = left; + memcpy(f->path + n, str, size); + f->path[n + size] = '\0'; + f->path_len += size; return n; } @@ -5650,6 +5649,7 @@ static void json_scanf_cb(void *callback_data, const char *name, size_t name_len, const char *path, const struct json_token *token) { struct json_scanf_info *info = (struct json_scanf_info *) callback_data; + char buf[32]; /* Must be enough to hold numbers */ (void) name; (void) name_len; @@ -5735,7 +5735,12 @@ static void json_scanf_cb(void *callback_data, const char *name, *(struct json_token *) info->target = *token; break; default: - info->num_conversions += sscanf(token->ptr, info->fmt, info->target); + /* Before scanf, copy into tmp buffer in order to 0-terminate it */ + if (token->len < (int) sizeof(buf)) { + memcpy(buf, token->ptr, token->len); + buf[token->len] = '\0'; + info->num_conversions += sscanf(buf, info->fmt, info->target); + } break; } } From 76f5a806d5c408312ba39fa820335aea7f16bd03 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 19:54:01 +0100 Subject: [PATCH 030/265] Lower conn accept message verbosity to DEBUG Raised in previous commit by mistake PUBLISHED_FROM=31a73fb610c34ed0c85d081bfa11a8067f216696 --- common/platforms/lwip/mg_lwip_net_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 5319b45..9502915 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -388,7 +388,7 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { struct mg_connection *lc = (struct mg_connection *) arg, *nc; struct mg_lwip_conn_state *lcs, *cs; struct tcp_pcb_listen *lpcb; - LOG(LL_INFO, + LOG(LL_DEBUG, ("%p conn %p from %s:%u", lc, newtpcb, IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port)); if (lc == NULL) { From 4418506e2b4b8cd2f7a7da375bcd44fde2558677 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 20:49:50 +0100 Subject: [PATCH 031/265] Do not close already closed connection PUBLISHED_FROM=9e345f2319141f20b89e28a2d29adba21ea213e1 --- common/platforms/lwip/mg_lwip_net_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 9502915..c5bd2ea 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -134,7 +134,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); if (p == NULL) { - if (nc != NULL) { + if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } else { /* Tombstoned connection, do nothing. */ From 49cb62520964a03a1d1153be7c232ef9f43e76bd Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 22 Jun 2017 20:40:04 +0100 Subject: [PATCH 032/265] Add chr() to mjs PUBLISHED_FROM=4bd6d65830fb1682b3d84ab2fe2eeb11e14b4241 --- README.md | 5 +++++ mjs.c | 11 +++++++++++ mjs/src/mjs_builtin.c | 11 +++++++++++ mjs/tests/unit_test.c | 22 ++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/README.md b/README.md index 1492dcf..301383b 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,11 @@ where it enables scripting for IoT devices.
Return numeric byte value at given string index. Example: 'abc'.at(0) === 0x61;
+
chr(n);
+
Return 1-byte string whose ASCII code is the integer `n`. If `n` is + not numeric or outside of `0-255` range, `null` is returned. Example: + chr(0x61) === 'a';
+
let a = [1,2,3,4,5]; a.splice(start, deleteCount, ...);
Change the contents of an array by removing existing elements and/or adding new elements. Example: diff --git a/mjs.c b/mjs.c index 577ab2d..b759712 100644 --- a/mjs.c +++ b/mjs.c @@ -6515,6 +6515,16 @@ static void mjs_get_mjs(struct mjs *mjs) { mjs_return(mjs, mjs_mk_foreign(mjs, mjs)); } +static void mjs_chr(struct mjs *mjs) { + mjs_val_t arg0 = mjs_arg(mjs, 0), res = MJS_NULL; + int n = mjs_get_int(mjs, arg0); + if (mjs_is_number(arg0) && n >= 0 && n <= 255) { + uint8_t s = n; + res = mjs_mk_string(mjs, (const char *) &s, sizeof(s), 1); + } + mjs_return(mjs, res); +} + static void mjs_do_gc(struct mjs *mjs) { mjs_val_t arg0 = mjs_arg(mjs, 0); mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0); @@ -6534,6 +6544,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); + mjs_set(mjs, obj, "chr", ~0, mjs_mk_foreign(mjs, mjs_chr)); /* * Populate JSON.parse() and JSON.stringify() diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index 20974c5..fde09e9 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -106,6 +106,16 @@ static void mjs_get_mjs(struct mjs *mjs) { mjs_return(mjs, mjs_mk_foreign(mjs, mjs)); } +static void mjs_chr(struct mjs *mjs) { + mjs_val_t arg0 = mjs_arg(mjs, 0), res = MJS_NULL; + int n = mjs_get_int(mjs, arg0); + if (mjs_is_number(arg0) && n >= 0 && n <= 255) { + uint8_t s = n; + res = mjs_mk_string(mjs, (const char *) &s, sizeof(s), 1); + } + mjs_return(mjs, res); +} + static void mjs_do_gc(struct mjs *mjs) { mjs_val_t arg0 = mjs_arg(mjs, 0); mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0); @@ -125,6 +135,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); + mjs_set(mjs, obj, "chr", ~0, mjs_mk_foreign(mjs, mjs_chr)); /* * Populate JSON.parse() and JSON.stringify() diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index ec59135..e60805a 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -37,6 +37,13 @@ extern "C" { ASSERT_EQ(mjs_get_double(mjs, res), (double) result); \ } while (0) +#define CHECK_TRUE(str) \ + do { \ + ASSERT_EXEC_OK(mjs_exec(mjs, str, &res)); \ + ASSERT_EQ(res, mjs_mk_boolean(mjs, 1)); \ + } while (0) + + /* * Like `RUN_TEST()`, but the test function should have a prototype * test_func_t. @@ -2558,6 +2565,21 @@ const char *test_string(struct mjs *mjs) { ASSERT_EXEC_OK(mjs_exec(mjs, "'\\xff'.at(1)", &res)); ASSERT_EQ(res, MJS_UNDEFINED); + /* chr(), error conditions - wrong argument */ + CHECK_TRUE("chr() === null;"); + CHECK_TRUE("chr('x') === null;"); + CHECK_TRUE("chr({}) === null;"); + CHECK_TRUE("chr([]) === null;"); + CHECK_TRUE("chr(false) === null;"); + CHECK_TRUE("chr(0x100) === null;"); + CHECK_TRUE("chr(-1) === null;"); + + /* chr(), success */ + CHECK_TRUE("chr(0) === '\\x00';"); + CHECK_TRUE("chr(1) === '\\x01';"); + CHECK_TRUE("chr(0x61) === 'a';"); + CHECK_TRUE("chr(0xff) === '\\xff';"); + /* concatenation */ ASSERT_EXEC_OK(mjs_exec(mjs, "'foo' + 'bar' === 'foobar'", &res)); From b21c17e62e46c27a0a2c224116fd05903129d5ae Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 26 Jun 2017 16:58:27 +0100 Subject: [PATCH 033/265] Fix print to not truncate str at \0 PUBLISHED_FROM=e219df17d02661308640bbce3d99ffd0559da7d7 --- mjs.c | 10 ++++++++-- mjs/src/mjs_util.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index b759712..9ebe68c 100644 --- a/mjs.c +++ b/mjs.c @@ -12528,9 +12528,15 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { } else if (mjs_is_boolean(v)) { fprintf(fp, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); } else if (mjs_is_string(v)) { - size_t size; + size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); - printf("%.*s", (int) size, s); + for (i = 0; i < size; i++) { + if (isprint(s[i])) { + putchar(s[i]); + } else { + printf("\\x%02x", ((unsigned char *) s)[i]); + } + } } else if (mjs_is_array(v)) { fprintf(fp, ""); } else if (mjs_is_object(v)) { diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index 42366b9..a72833c 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -55,9 +55,15 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { } else if (mjs_is_boolean(v)) { fprintf(fp, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); } else if (mjs_is_string(v)) { - size_t size; + size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); - printf("%.*s", (int) size, s); + for (i = 0; i < size; i++) { + if (isprint(s[i])) { + putchar(s[i]); + } else { + printf("\\x%02x", ((unsigned char *) s)[i]); + } + } } else if (mjs_is_array(v)) { fprintf(fp, ""); } else if (mjs_is_object(v)) { From 78735dca3f601f1dba5df2b62114579daaf86125 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 26 Jun 2017 17:35:45 +0100 Subject: [PATCH 034/265] Fix my fix PUBLISHED_FROM=204e8d030e941f9bb07e9495ebab266811f5ebeb --- mjs.c | 7 ++++--- mjs/src/mjs_util.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mjs.c b/mjs.c index 9ebe68c..df2b3a6 100644 --- a/mjs.c +++ b/mjs.c @@ -12531,10 +12531,11 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); for (i = 0; i < size; i++) { - if (isprint(s[i])) { - putchar(s[i]); + int ch = ((unsigned char *) s)[i]; + if (isprint(ch)) { + putchar(ch); } else { - printf("\\x%02x", ((unsigned char *) s)[i]); + printf("\\x%02x", ch); } } } else if (mjs_is_array(v)) { diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index a72833c..15d7dcd 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -58,10 +58,11 @@ void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); for (i = 0; i < size; i++) { - if (isprint(s[i])) { - putchar(s[i]); + int ch = ((unsigned char *) s)[i]; + if (isprint(ch)) { + putchar(ch); } else { - printf("\\x%02x", ((unsigned char *) s)[i]); + printf("\\x%02x", ch); } } } else if (mjs_is_array(v)) { From f10985a849dee75be0212b2d3109e44c27a53d01 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 27 Jun 2017 16:06:21 +0100 Subject: [PATCH 035/265] Don't define fileno stub in C++ PUBLISHED_FROM=98fb6c78d20a98dfba07ba6671bd51a394bbc4ca --- common/platforms/platform_esp8266.h | 2 +- mjs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/platforms/platform_esp8266.h b/common/platforms/platform_esp8266.h index 1c84807..6a4d547 100644 --- a/common/platforms/platform_esp8266.h +++ b/common/platforms/platform_esp8266.h @@ -29,7 +29,7 @@ typedef struct stat cs_stat_t; #define __cdecl #define _FILE_OFFSET_BITS 32 -#ifndef RTOS_SDK +#if !defined(RTOS_SDK) && !defined(__cplusplus) #define fileno(x) -1 #endif diff --git a/mjs.c b/mjs.c index df2b3a6..cd57375 100644 --- a/mjs.c +++ b/mjs.c @@ -516,7 +516,7 @@ typedef struct stat cs_stat_t; #define __cdecl #define _FILE_OFFSET_BITS 32 -#ifndef RTOS_SDK +#if !defined(RTOS_SDK) && !defined(__cplusplus) #define fileno(x) -1 #endif From 3aa0138841f84089dc7d90fc21360bec694a3e5d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 27 Jun 2017 17:57:50 +0100 Subject: [PATCH 036/265] Do not require fw bin for debug_coredump, use ELF Map sections of the ELF file and read from them as required. PUBLISHED_FROM=46cc15479bbf3314aa7598f88f166a1a932fc40b --- common/platforms/esp/debug_coredump.mk | 4 +--- common/platforms/esp/serve_core.py | 33 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/common/platforms/esp/debug_coredump.mk b/common/platforms/esp/debug_coredump.mk index 2caaa8f..6c095f0 100644 --- a/common/platforms/esp/debug_coredump.mk +++ b/common/platforms/esp/debug_coredump.mk @@ -12,15 +12,13 @@ endif -v $(APP_MOUNT_PATH):$(DOCKER_APP_PATH) \ -v $(MGOS_PATH_ABS):$(DOCKER_MGOS_PATH) \ -v $(MGOS_PATH_ABS):$(MGOS_PATH_ABS) \ - -v $(realpath $(BIN_FILE)):/app.bin \ -v $(realpath $(ELF_FILE)):/app.elf \ -v $(realpath $(CONSOLE_LOG)):/console.log \ $(SDK_VERSION) /bin/bash -c "\ cd $(DOCKER_APP_PATH)/$(APP_SUBDIR); \ $(DOCKER_MGOS_PATH)/common/platforms/esp/serve_core.py \ --rom $(DOCKER_MGOS_PATH)/common/platforms/$(APP_PLATFORM)/rom/rom.bin \ - --irom /app.bin --irom_addr $(IROM_MAP_ADDR) \ - /console.log & \ + /app.elf /console.log & \ $(GDB) /app.elf \ -ex 'target remote 127.0.0.1:1234' \ -ex 'set confirm off' \ diff --git a/common/platforms/esp/serve_core.py b/common/platforms/esp/serve_core.py index 6e1a6a6..adc0526 100755 --- a/common/platforms/esp/serve_core.py +++ b/common/platforms/esp/serve_core.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -# usage: tools/serve_core.py --iram firmware/0x00000.bin --irom firmware/0x11000.bin /tmp/esp-console.log +# usage: tools/serve_core.py build/fw/objs/fw.elf /tmp/console.log # # Then you can connect with gdb. The ESP8266 SDK image provides a debugger with # reasonable support of lx106. Example invocation: @@ -24,21 +24,16 @@ import struct import sys -IRAM_BASE=0x40100000 -IROM_BASE=0x40200000 +import elftools.elf.elffile # apt install python-pyelftools + ROM_BASE= 0x40000000 parser = argparse.ArgumentParser(description='Serve ESP core dump to GDB') parser.add_argument('--port', dest='port', default=1234, type=int, help='listening port') -parser.add_argument('--iram', dest='iram', help='iram firmware section') -parser.add_argument('--iram_addr', dest='iram_addr', - type=lambda x: int(x,16), help='iram firmware section') -parser.add_argument('--irom', dest='irom', required=False, help='irom firmware section') -parser.add_argument('--irom_addr', dest='irom_addr', - type=lambda x: int(x,16), help='irom firmware section') parser.add_argument('--rom', dest='rom', required=False, help='rom section') parser.add_argument('--rom_addr', dest='rom_addr', default=ROM_BASE, type=lambda x: int(x,16), help='rom section') +parser.add_argument('elf', help='Program executable') parser.add_argument('log', help='serial log containing core dump snippet') args = parser.parse_args() @@ -79,12 +74,9 @@ class Core(object): def __init__(self, filename): self._dump = self._read(filename) self.mem = self._map_core(self._dump) - if args.iram: - self.mem.extend(self._map_firmware(args.iram_addr, args.iram, IRAM_BASE)) - if args.irom: - self.mem.extend(self._map_firmware(args.irom_addr, args.irom, IROM_BASE)) if args.rom_addr: self.mem.extend(self._map_firmware(args.rom_addr, args.rom, ROM_BASE)) + self.mem.extend(self._map_elf(args.elf)) self.regs = base64.decodestring(self._dump['REGS']['data']) self.tasks = dict((a, self._parse_tcb(a)) for a in self._dump.get('tasks', [])) @@ -172,6 +164,21 @@ def _map_firmware(self, addr, filename, base): result.append((addr, addr + len(data), data)) return result + def _map_elf(self, elf_file_name): + result = [] + f = open(elf_file_name) + ef = elftools.elf.elffile.ELFFile(f) + for i, sec in enumerate(ef.iter_sections()): + addr, size, off = sec["sh_addr"], sec["sh_size"], sec["sh_offset"] + if addr > 0 and size > 0: + print >>sys.stderr, "Mapping {0}: {1} @ {2:#02x}".format(sec.name, size, addr) + f.seek(off) + assert f.tell() == off + data = f.read(size) + assert len(data) == size + result.append((addr, addr + size, data)) + return result + def read(self, addr, size): for base, end, data in self.mem: if addr >= base and addr < end: From cf4208d0cff362e261014fc2109b20905c2dd617 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Wed, 28 Jun 2017 19:18:42 +0100 Subject: [PATCH 037/265] Commonize pattern matching functions PUBLISHED_FROM=e69e298a51dbe0f9c47184169ecad06eef0676fc --- common/str_util.c | 92 +++++++++++++++++++++++ common/str_util.h | 27 +++++++ mjs.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+) diff --git a/common/str_util.c b/common/str_util.c index 0778880..7758571 100644 --- a/common/str_util.c +++ b/common/str_util.c @@ -405,4 +405,96 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { return len; } +const char *mg_next_comma_list_entry(const char *, struct mg_str *, + struct mg_str *) WEAK; +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val) { + if (list == NULL || *list == '\0') { + /* End of the list */ + list = NULL; + } else { + val->p = list; + if ((list = strchr(val->p, ',')) != NULL) { + /* Comma found. Store length and shift the list ptr */ + val->len = list - val->p; + list++; + } else { + /* This value is the last one */ + list = val->p + strlen(val->p); + val->len = list - val->p; + } + + if (eq_val != NULL) { + /* Value has form "x=y", adjust pointers and lengths */ + /* so that val points to "x", and eq_val points to "y". */ + eq_val->len = 0; + eq_val->p = (const char *) memchr(val->p, '=', val->len); + if (eq_val->p != NULL) { + eq_val->p++; /* Skip over '=' character */ + eq_val->len = val->p + val->len - eq_val->p; + val->len = (eq_val->p - val->p) - 1; + } + } + } + + return list; +} + +int mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK; +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) { + const char *or_str; + size_t len, i = 0, j = 0; + int res; + + if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL || + (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) { + struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)}; + res = mg_match_prefix_n(pstr, str); + if (res > 0) return res; + pstr.p = or_str + 1; + pstr.len = (pattern.p + pattern.len) - (or_str + 1); + return mg_match_prefix_n(pstr, str); + } + + for (; i < pattern.len; i++, j++) { + if (pattern.p[i] == '?' && j != str.len) { + continue; + } else if (pattern.p[i] == '$') { + return j == str.len ? (int) j : -1; + } else if (pattern.p[i] == '*') { + i++; + if (i < pattern.len && pattern.p[i] == '*') { + i++; + len = str.len - j; + } else { + len = 0; + while (j + len != str.len && str.p[j + len] != '/') { + len++; + } + } + if (i == pattern.len) { + return j + len; + } + do { + const struct mg_str pstr = {pattern.p + i, pattern.len - i}; + const struct mg_str sstr = {str.p + j + len, str.len - j - len}; + res = mg_match_prefix_n(pstr, sstr); + } while (res == -1 && len-- > 0); + return res == -1 ? -1 : (int) (j + res + len); + } else if (str_util_lowercase(&pattern.p[i]) != + str_util_lowercase(&str.p[j])) { + return -1; + } + } + return j; +} + +int mg_match_prefix(const char *, int, const char *) WEAK; +int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { + const struct mg_str pstr = {pattern, (size_t) pattern_len}; + struct mg_str s = {str, 0}; + if (str != NULL) s.len = strlen(str); + return mg_match_prefix_n(pstr, s); +} + #endif /* EXCLUDE_COMMON */ diff --git a/common/str_util.h b/common/str_util.h index 08e907c..888f76d 100644 --- a/common/str_util.h +++ b/common/str_util.h @@ -10,6 +10,7 @@ #include #include "common/platform.h" +#include "common/mg_str.h" #ifndef CS_ENABLE_STRDUP #define CS_ENABLE_STRDUP 0 @@ -104,6 +105,32 @@ int mg_asprintf(char **buf, size_t size, const char *fmt, ...); /* Same as mg_asprintf, but takes varargs list. */ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); +/* + * A helper function for traversing a comma separated list of values. + * It returns a list pointer shifted to the next value or NULL if the end + * of the list found. + * The value is stored in a val vector. If the value has a form "x=y", then + * eq_val vector is initialised to point to the "y" part, and val vector length + * is adjusted to point only to "x". + * If the list is just a comma separated list of entries, like "aa,bb,cc" then + * `eq_val` will contain zero-length string. + * + * The purpose of this function is to parse comma separated string without + * any copying/memory allocation. + */ +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val); + +/* + * Matches 0-terminated string (mg_match_prefix) or string with given length + * mg_match_prefix_n against a glob pattern. + * + * Match is case-insensitive. Returns number of bytes matched, or -1 if no + * match. + */ +int mg_match_prefix(const char *pattern, int pattern_len, const char *str); +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); + #ifdef __cplusplus } #endif diff --git a/mjs.c b/mjs.c index cd57375..40c0dff 100644 --- a/mjs.c +++ b/mjs.c @@ -1655,6 +1655,73 @@ void mbuf_trim(struct mbuf *); #endif /* CS_COMMON_MG_MEM_H_ */ #ifdef MJS_MODULE_LINES +#line 1 "common/mg_str.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MG_STR_H_ +#define CS_COMMON_MG_STR_H_ + +#include + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Describes chunk of memory */ +struct mg_str { + const char *p; /* Memory chunk pointer */ + size_t len; /* Memory chunk length */ +}; + +/* + * Helper functions for creating mg_str struct from plain C string. + * `NULL` is allowed and becomes `{NULL, 0}`. + */ +struct mg_str mg_mk_str(const char *s); +struct mg_str mg_mk_str_n(const char *s, size_t len); + +/* Macro for initializing mg_str. */ +#define MG_MK_STR(str_literal) \ + { str_literal, sizeof(str_literal) - 1 } +#define MG_NULL_STR \ + { NULL, 0 } + +/* + * Cross-platform version of `strcmp()` where where first string is + * specified by `struct mg_str`. + */ +int mg_vcmp(const struct mg_str *str2, const char *str1); + +/* + * Cross-platform version of `strncasecmp()` where first string is + * specified by `struct mg_str`. + */ +int mg_vcasecmp(const struct mg_str *str2, const char *str1); + +/* Creates a copy of s (heap-allocated). */ +struct mg_str mg_strdup(const struct mg_str s); + +/* + * Creates a copy of s (heap-allocated). + * Resulting string is NUL-terminated (but NUL is not included in len). + */ +struct mg_str mg_strdup_nul(const struct mg_str s); + +int mg_strcmp(const struct mg_str str1, const struct mg_str str2); +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MG_STR_H_ */ +#ifdef MJS_MODULE_LINES #line 1 "common/str_util.h" #endif /* @@ -1669,6 +1736,7 @@ void mbuf_trim(struct mbuf *); #include /* Amalgamated: #include "common/platform.h" */ +/* Amalgamated: #include "common/mg_str.h" */ #ifndef CS_ENABLE_STRDUP #define CS_ENABLE_STRDUP 0 @@ -1763,6 +1831,32 @@ int mg_asprintf(char **buf, size_t size, const char *fmt, ...); /* Same as mg_asprintf, but takes varargs list. */ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); +/* + * A helper function for traversing a comma separated list of values. + * It returns a list pointer shifted to the next value or NULL if the end + * of the list found. + * The value is stored in a val vector. If the value has a form "x=y", then + * eq_val vector is initialised to point to the "y" part, and val vector length + * is adjusted to point only to "x". + * If the list is just a comma separated list of entries, like "aa,bb,cc" then + * `eq_val` will contain zero-length string. + * + * The purpose of this function is to parse comma separated string without + * any copying/memory allocation. + */ +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val); + +/* + * Matches 0-terminated string (mg_match_prefix) or string with given length + * mg_match_prefix_n against a glob pattern. + * + * Match is case-insensitive. Returns number of bytes matched, or -1 if no + * match. + */ +int mg_match_prefix(const char *pattern, int pattern_len, const char *str); +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); + #ifdef __cplusplus } #endif @@ -4785,6 +4879,98 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { return len; } +const char *mg_next_comma_list_entry(const char *, struct mg_str *, + struct mg_str *) WEAK; +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val) { + if (list == NULL || *list == '\0') { + /* End of the list */ + list = NULL; + } else { + val->p = list; + if ((list = strchr(val->p, ',')) != NULL) { + /* Comma found. Store length and shift the list ptr */ + val->len = list - val->p; + list++; + } else { + /* This value is the last one */ + list = val->p + strlen(val->p); + val->len = list - val->p; + } + + if (eq_val != NULL) { + /* Value has form "x=y", adjust pointers and lengths */ + /* so that val points to "x", and eq_val points to "y". */ + eq_val->len = 0; + eq_val->p = (const char *) memchr(val->p, '=', val->len); + if (eq_val->p != NULL) { + eq_val->p++; /* Skip over '=' character */ + eq_val->len = val->p + val->len - eq_val->p; + val->len = (eq_val->p - val->p) - 1; + } + } + } + + return list; +} + +int mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK; +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) { + const char *or_str; + size_t len, i = 0, j = 0; + int res; + + if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL || + (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) { + struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)}; + res = mg_match_prefix_n(pstr, str); + if (res > 0) return res; + pstr.p = or_str + 1; + pstr.len = (pattern.p + pattern.len) - (or_str + 1); + return mg_match_prefix_n(pstr, str); + } + + for (; i < pattern.len; i++, j++) { + if (pattern.p[i] == '?' && j != str.len) { + continue; + } else if (pattern.p[i] == '$') { + return j == str.len ? (int) j : -1; + } else if (pattern.p[i] == '*') { + i++; + if (i < pattern.len && pattern.p[i] == '*') { + i++; + len = str.len - j; + } else { + len = 0; + while (j + len != str.len && str.p[j + len] != '/') { + len++; + } + } + if (i == pattern.len) { + return j + len; + } + do { + const struct mg_str pstr = {pattern.p + i, pattern.len - i}; + const struct mg_str sstr = {str.p + j + len, str.len - j - len}; + res = mg_match_prefix_n(pstr, sstr); + } while (res == -1 && len-- > 0); + return res == -1 ? -1 : (int) (j + res + len); + } else if (str_util_lowercase(&pattern.p[i]) != + str_util_lowercase(&str.p[j])) { + return -1; + } + } + return j; +} + +int mg_match_prefix(const char *, int, const char *) WEAK; +int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { + const struct mg_str pstr = {pattern, (size_t) pattern_len}; + struct mg_str s = {str, 0}; + if (str != NULL) s.len = strlen(str); + return mg_match_prefix_n(pstr, s); +} + #endif /* EXCLUDE_COMMON */ #ifdef MJS_MODULE_LINES #line 1 "frozen/frozen.c" From afa9205fde9a20587eebf0f34f0e9d2022f7b97c Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 29 Jun 2017 15:21:03 +0100 Subject: [PATCH 038/265] Introduce log filter PUBLISHED_FROM=b8f538f87e034452032284d45b78090338e87f72 --- common/cs_dbg.c | 30 +++- common/cs_dbg.h | 28 ++-- mjs.c | 400 +++++++++++++++++++++++++----------------------- 3 files changed, 253 insertions(+), 205 deletions(-) diff --git a/common/cs_dbg.c b/common/cs_dbg.c index 4c7369d..33a7632 100644 --- a/common/cs_dbg.c +++ b/common/cs_dbg.c @@ -10,6 +10,7 @@ #include #include "common/cs_time.h" +#include "common/str_util.h" enum cs_log_level cs_log_threshold WEAK = #if CS_ENABLE_DEBUG @@ -18,6 +19,9 @@ enum cs_log_level cs_log_threshold WEAK = LL_ERROR; #endif +static char *s_filter_pattern = NULL; +static size_t s_filter_pattern_len; + #if CS_ENABLE_STDIO FILE *cs_log_file WEAK = NULL; @@ -28,9 +32,30 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_print_prefix(enum cs_log_level level, const char *func) WEAK; -void cs_log_print_prefix(enum cs_log_level level, const char *func) { +void cs_log_set_filter(char *str) WEAK; +void cs_log_set_filter(char *str) { + free(s_filter_pattern); + if (str != NULL) { + s_filter_pattern = strdup(str); + s_filter_pattern_len = strlen(str); + } else { + s_filter_pattern = NULL; + s_filter_pattern_len = 0; + } +}; + +int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename) { char prefix[21]; + + if (level > cs_log_threshold) return 0; + if (s_filter_pattern != NULL && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) < 0 && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) < 0) { + return 0; + } + strncpy(prefix, func, 20); prefix[20] = '\0'; if (cs_log_file == NULL) cs_log_file = stderr; @@ -43,6 +68,7 @@ void cs_log_print_prefix(enum cs_log_level level, const char *func) { cs_log_ts = now; } #endif + return 1; } void cs_log_printf(const char *fmt, ...) WEAK; diff --git a/common/cs_dbg.h b/common/cs_dbg.h index cca04a3..0942de7 100644 --- a/common/cs_dbg.h +++ b/common/cs_dbg.h @@ -36,36 +36,34 @@ enum cs_log_level { _LL_MAX = 5, }; +/* Set log level. */ void cs_log_set_level(enum cs_log_level level); +/* Set log filter. NULL (a default) logs everything. */ +void cs_log_set_filter(char *source_file_name); + +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename); + +extern enum cs_log_level cs_log_threshold; + #if CS_ENABLE_STDIO void cs_log_set_file(FILE *file); -extern enum cs_log_level cs_log_threshold; -void cs_log_print_prefix(enum cs_log_level level, const char *func); void cs_log_printf(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; -#define LOG(l, x) \ - do { \ - if (cs_log_threshold >= l) { \ - cs_log_print_prefix(l, __func__); \ - cs_log_printf x; \ - } \ +#define LOG(l, x) \ + do { \ + if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ } while (0) #ifndef CS_NDEBUG -#define DBG(x) \ - do { \ - if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ - cs_log_print_prefix(LL_VERBOSE_DEBUG, __func__); \ - cs_log_printf x; \ - } \ - } while (0) +#define DBG(x) LOG(LL_VERBOSE_DEBUG, x) #else /* NDEBUG */ diff --git a/mjs.c b/mjs.c index 40c0dff..e02cd2c 100644 --- a/mjs.c +++ b/mjs.c @@ -1409,36 +1409,34 @@ enum cs_log_level { _LL_MAX = 5, }; +/* Set log level. */ void cs_log_set_level(enum cs_log_level level); +/* Set log filter. NULL (a default) logs everything. */ +void cs_log_set_filter(char *source_file_name); + +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename); + +extern enum cs_log_level cs_log_threshold; + #if CS_ENABLE_STDIO void cs_log_set_file(FILE *file); -extern enum cs_log_level cs_log_threshold; -void cs_log_print_prefix(enum cs_log_level level, const char *func); void cs_log_printf(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; -#define LOG(l, x) \ - do { \ - if (cs_log_threshold >= l) { \ - cs_log_print_prefix(l, __func__); \ - cs_log_printf x; \ - } \ +#define LOG(l, x) \ + do { \ + if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ } while (0) #ifndef CS_NDEBUG -#define DBG(x) \ - do { \ - if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ - cs_log_print_prefix(LL_VERBOSE_DEBUG, __func__); \ - cs_log_printf x; \ - } \ - } while (0) +#define DBG(x) LOG(LL_VERBOSE_DEBUG, x) #else /* NDEBUG */ @@ -1484,177 +1482,6 @@ double cs_time(void); #endif /* CS_COMMON_CS_TIME_H_ */ #ifdef MJS_MODULE_LINES -#line 1 "common/cs_file.h" -#endif -/* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_CS_FILE_H_ -#define CS_COMMON_CS_FILE_H_ - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Read whole file `path` in memory. It is responsibility of the caller - * to `free()` allocated memory. File content is guaranteed to be - * '\0'-terminated. File size is returned in `size` variable, which does not - * count terminating `\0`. - * Return: allocated memory, or NULL on error. - */ -char *cs_read_file(const char *path, size_t *size); - -#ifdef CS_MMAP -char *cs_mmap_file(const char *path, size_t *size); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_CS_FILE_H_ */ -#ifdef MJS_MODULE_LINES -#line 1 "common/cs_varint.h" -#endif -/* - * Copyright (c) 2014-2017 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_CS_VARINT_H_ -#define CS_COMMON_CS_VARINT_H_ - -#include - -#if defined(__cplusplus) -extern "C" { -#endif /* __cplusplus */ - -int cs_varint_encode(uint64_t num, uint8_t *to); -uint64_t cs_varint_decode(const uint8_t *from, int *llen); -int cs_varint_llen(uint64_t num); - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_CS_VARINT_H_ */ -#ifdef MJS_MODULE_LINES -#line 1 "common/mbuf.h" -#endif -/* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved - */ - -/* - * === Memory Buffers - * - * Mbufs are mutable/growing memory buffers, like C++ strings. - * Mbuf can append data to the end of a buffer or insert data into arbitrary - * position in the middle of a buffer. The buffer grows automatically when - * needed. - */ - -#ifndef CS_COMMON_MBUF_H_ -#define CS_COMMON_MBUF_H_ - -#include -/* Amalgamated: #include "common/platform.h" */ - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef MBUF_SIZE_MULTIPLIER -#define MBUF_SIZE_MULTIPLIER 1.5 -#endif - -/* Memory buffer descriptor */ -struct mbuf { - char *buf; /* Buffer pointer */ - size_t len; /* Data length. Data is located between offset 0 and len. */ - size_t size; /* Buffer size allocated by realloc(1). Must be >= len */ -}; - -/* - * Initialises an Mbuf. - * `initial_capacity` specifies the initial capacity of the mbuf. - */ -void mbuf_init(struct mbuf *, size_t initial_capacity); - -/* Frees the space allocated for the mbuffer and resets the mbuf structure. */ -void mbuf_free(struct mbuf *); - -/* - * Appends data to the Mbuf. - * - * Returns the number of bytes appended or 0 if out of memory. - */ -size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); - -/* - * Inserts data at a specified offset in the Mbuf. - * - * Existing data will be shifted forwards and the buffer will - * be grown if necessary. - * Returns the number of bytes inserted. - */ -size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t); - -/* Removes `data_size` bytes from the beginning of the buffer. */ -void mbuf_remove(struct mbuf *, size_t data_size); - -/* - * Resizes an Mbuf. - * - * If `new_size` is smaller than buffer's `len`, the - * resize is not performed. - */ -void mbuf_resize(struct mbuf *, size_t new_size); - -/* Shrinks an Mbuf by resizing its `size` to `len`. */ -void mbuf_trim(struct mbuf *); - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MBUF_H_ */ -#ifdef MJS_MODULE_LINES -#line 1 "common/mg_mem.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_MG_MEM_H_ -#define CS_COMMON_MG_MEM_H_ - -#ifndef MG_MALLOC -#define MG_MALLOC malloc -#endif - -#ifndef MG_CALLOC -#define MG_CALLOC calloc -#endif - -#ifndef MG_REALLOC -#define MG_REALLOC realloc -#endif - -#ifndef MG_FREE -#define MG_FREE free -#endif - -#endif /* CS_COMMON_MG_MEM_H_ */ -#ifdef MJS_MODULE_LINES #line 1 "common/mg_str.h" #endif /* @@ -1863,6 +1690,177 @@ int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); #endif /* CS_COMMON_STR_UTIL_H_ */ #ifdef MJS_MODULE_LINES +#line 1 "common/cs_file.h" +#endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_CS_FILE_H_ +#define CS_COMMON_CS_FILE_H_ + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Read whole file `path` in memory. It is responsibility of the caller + * to `free()` allocated memory. File content is guaranteed to be + * '\0'-terminated. File size is returned in `size` variable, which does not + * count terminating `\0`. + * Return: allocated memory, or NULL on error. + */ +char *cs_read_file(const char *path, size_t *size); + +#ifdef CS_MMAP +char *cs_mmap_file(const char *path, size_t *size); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_CS_FILE_H_ */ +#ifdef MJS_MODULE_LINES +#line 1 "common/cs_varint.h" +#endif +/* + * Copyright (c) 2014-2017 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_CS_VARINT_H_ +#define CS_COMMON_CS_VARINT_H_ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +int cs_varint_encode(uint64_t num, uint8_t *to); +uint64_t cs_varint_decode(const uint8_t *from, int *llen); +int cs_varint_llen(uint64_t num); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_CS_VARINT_H_ */ +#ifdef MJS_MODULE_LINES +#line 1 "common/mbuf.h" +#endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ + +/* + * === Memory Buffers + * + * Mbufs are mutable/growing memory buffers, like C++ strings. + * Mbuf can append data to the end of a buffer or insert data into arbitrary + * position in the middle of a buffer. The buffer grows automatically when + * needed. + */ + +#ifndef CS_COMMON_MBUF_H_ +#define CS_COMMON_MBUF_H_ + +#include +/* Amalgamated: #include "common/platform.h" */ + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef MBUF_SIZE_MULTIPLIER +#define MBUF_SIZE_MULTIPLIER 1.5 +#endif + +/* Memory buffer descriptor */ +struct mbuf { + char *buf; /* Buffer pointer */ + size_t len; /* Data length. Data is located between offset 0 and len. */ + size_t size; /* Buffer size allocated by realloc(1). Must be >= len */ +}; + +/* + * Initialises an Mbuf. + * `initial_capacity` specifies the initial capacity of the mbuf. + */ +void mbuf_init(struct mbuf *, size_t initial_capacity); + +/* Frees the space allocated for the mbuffer and resets the mbuf structure. */ +void mbuf_free(struct mbuf *); + +/* + * Appends data to the Mbuf. + * + * Returns the number of bytes appended or 0 if out of memory. + */ +size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); + +/* + * Inserts data at a specified offset in the Mbuf. + * + * Existing data will be shifted forwards and the buffer will + * be grown if necessary. + * Returns the number of bytes inserted. + */ +size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t); + +/* Removes `data_size` bytes from the beginning of the buffer. */ +void mbuf_remove(struct mbuf *, size_t data_size); + +/* + * Resizes an Mbuf. + * + * If `new_size` is smaller than buffer's `len`, the + * resize is not performed. + */ +void mbuf_resize(struct mbuf *, size_t new_size); + +/* Shrinks an Mbuf by resizing its `size` to `len`. */ +void mbuf_trim(struct mbuf *); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MBUF_H_ */ +#ifdef MJS_MODULE_LINES +#line 1 "common/mg_mem.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MG_MEM_H_ +#define CS_COMMON_MG_MEM_H_ + +#ifndef MG_MALLOC +#define MG_MALLOC malloc +#endif + +#ifndef MG_CALLOC +#define MG_CALLOC calloc +#endif + +#ifndef MG_REALLOC +#define MG_REALLOC realloc +#endif + +#ifndef MG_FREE +#define MG_FREE free +#endif + +#endif /* CS_COMMON_MG_MEM_H_ */ +#ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.h" #endif /* @@ -4186,6 +4184,7 @@ int json_escape(struct json_out *out, const char *str, size_t str_len); #include /* Amalgamated: #include "common/cs_time.h" */ +/* Amalgamated: #include "common/str_util.h" */ enum cs_log_level cs_log_threshold WEAK = #if CS_ENABLE_DEBUG @@ -4194,6 +4193,9 @@ enum cs_log_level cs_log_threshold WEAK = LL_ERROR; #endif +static char *s_filter_pattern = NULL; +static size_t s_filter_pattern_len; + #if CS_ENABLE_STDIO FILE *cs_log_file WEAK = NULL; @@ -4204,9 +4206,30 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_print_prefix(enum cs_log_level level, const char *func) WEAK; -void cs_log_print_prefix(enum cs_log_level level, const char *func) { +void cs_log_set_filter(char *str) WEAK; +void cs_log_set_filter(char *str) { + free(s_filter_pattern); + if (str != NULL) { + s_filter_pattern = strdup(str); + s_filter_pattern_len = strlen(str); + } else { + s_filter_pattern = NULL; + s_filter_pattern_len = 0; + } +}; + +int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename) { char prefix[21]; + + if (level > cs_log_threshold) return 0; + if (s_filter_pattern != NULL && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) < 0 && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) < 0) { + return 0; + } + strncpy(prefix, func, 20); prefix[20] = '\0'; if (cs_log_file == NULL) cs_log_file = stderr; @@ -4219,6 +4242,7 @@ void cs_log_print_prefix(enum cs_log_level level, const char *func) { cs_log_ts = now; } #endif + return 1; } void cs_log_printf(const char *fmt, ...) WEAK; From 6b25e1fd29b3acd7c65c6c5d95be3f676ee69853 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 29 Jun 2017 15:46:55 +0100 Subject: [PATCH 039/265] BREAKING: Increase FS to 256K; change flash layout With this change we increase default FS size to 256K and change the flash layout on ESP8266. On ESP32 the change is less drastic, since it has partition table. On ESP8266 it is no longer possible to flash FW build with 4M layout on a smaller device, but it is still possible to select 1M or 2M layout by setting FLASH_SIZE. However, in both cases the chage is not compatible with OTA, it's not possible to perform OTA from FW before this change to FW after it. Hopefully this is the last time we do this. Also, we use this opportunity to enable SPIFFS file metadata on ESP8266. CC3200 is not affected because it has no space on flash left. PUBLISHED_FROM=95becfb67814d2f7ddebe1af2ba41baf8db4502a --- common/platforms/esp8266/rboot/rboot/rboot.c | 4 ++-- common/platforms/esp8266/rboot/rboot/rboot.h | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/common/platforms/esp8266/rboot/rboot/rboot.c b/common/platforms/esp8266/rboot/rboot/rboot.c index e6325d7..1850486 100644 --- a/common/platforms/esp8266/rboot/rboot/rboot.c +++ b/common/platforms/esp8266/rboot/rboot/rboot.c @@ -266,7 +266,7 @@ uint32 NOINLINE find_image(void) { #endif ) { /* Modified by Cesanta */ - ets_printf("Writing default boot config.\r\n"); + ets_printf("Writing default boot config @ 0x%x.\r\n", BOOT_CONFIG_SECTOR * SECTOR_SIZE); ets_memset(romconf, 0x00, sizeof(rboot_config)); romconf->magic = BOOT_CONFIG_MAGIC; romconf->version = BOOT_CONFIG_VERSION; @@ -366,7 +366,7 @@ uint32 NOINLINE find_image(void) { SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } - ets_printf("Booting rom %d.\r\n", romToBoot); + ets_printf("Booting rom %d (0x%x).\r\n", romToBoot, romconf->roms[romToBoot]); // copy the loader to top of iram ets_memcpy((void*)_text_addr, _text_data, _text_len); // return address to load from diff --git a/common/platforms/esp8266/rboot/rboot/rboot.h b/common/platforms/esp8266/rboot/rboot/rboot.h index 4a28031..3949d74 100644 --- a/common/platforms/esp8266/rboot/rboot/rboot.h +++ b/common/platforms/esp8266/rboot/rboot/rboot.h @@ -32,7 +32,12 @@ extern "C" { #define CHKSUM_INIT 0xef #define SECTOR_SIZE 0x1000 -#define BOOT_CONFIG_SECTOR 1 + +#ifndef BOOT_CONFIG_ADDR +#define BOOT_CONFIG_ADDR 0x1000 +#endif + +#define BOOT_CONFIG_SECTOR (BOOT_CONFIG_ADDR / SECTOR_SIZE) #define BOOT_CONFIG_MAGIC 0xe1 #define BOOT_CONFIG_VERSION 0x01 From e8963e0ea21524a1148ec303cc92e010c6cdb709 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jun 2017 12:10:44 +0100 Subject: [PATCH 040/265] Handle %c in json_printf() PUBLISHED_FROM=98e913b0043585af159a55e1fef4d192d88dbd4e --- frozen/frozen.c | 2 +- mjs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index dcd77e4..1606d1d 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -630,7 +630,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { * TODO(dfrank): reimplement %s and %.*s in order to avoid that. */ - const char *end_of_format_specifier = "sdfFgGlhuI.*-0123456789"; + const char *end_of_format_specifier = "sdfFgGlhuIc.*-0123456789"; size_t n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; size_t need_len; diff --git a/mjs.c b/mjs.c index e02cd2c..a1e1fab 100644 --- a/mjs.c +++ b/mjs.c @@ -5631,7 +5631,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { * TODO(dfrank): reimplement %s and %.*s in order to avoid that. */ - const char *end_of_format_specifier = "sdfFgGlhuI.*-0123456789"; + const char *end_of_format_specifier = "sdfFgGlhuIc.*-0123456789"; size_t n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; size_t need_len; From 75f2612f083d9c16dcf998abee686fa172f95965 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jun 2017 14:48:34 +0300 Subject: [PATCH 041/265] Use LOG for mjs debug dump PUBLISHED_FROM=ca274fc136f9154ceec702d152ab7ab9e3f99486 --- mjs.c | 131 ++++++++++++++++++++------------------ mjs.h | 5 +- mjs/src/mjs_exec.c | 10 +-- mjs/src/mjs_util.c | 114 ++++++++++++++++++--------------- mjs/src/mjs_util.h | 2 +- mjs/src/mjs_util_public.h | 5 +- 6 files changed, 143 insertions(+), 124 deletions(-) diff --git a/mjs.c b/mjs.c index a1e1fab..2f71404 100644 --- a/mjs.c +++ b/mjs.c @@ -3330,11 +3330,12 @@ extern "C" { const char *mjs_typeof(mjs_val_t v); void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp); +void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t buflen); #if MJS_ENABLE_DEBUG -void mjs_disasm(const uint8_t *code, size_t len, FILE *fp); -void mjs_dump(struct mjs *mjs, int do_disasm, FILE *fp); +void mjs_disasm(const uint8_t *code, size_t len); +void mjs_dump(struct mjs *mjs, int do_disasm); #endif @@ -3382,7 +3383,7 @@ extern "C" { struct mjs_bcode_part; MJS_PRIVATE const char *opcodetostr(uint8_t opcode); -MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp); +MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i); MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t); /* @@ -7849,11 +7850,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { #endif const uint8_t *code = (const uint8_t *) bp.data.p; - if (cs_log_threshold >= LL_VERBOSE_DEBUG) { - /* mjs_dump(mjs, 0, stdout); */ - printf("executing: "); - mjs_disasm_single(code, i, stdout); - } + mjs_disasm_single(code, i); prev_opcode = opcode; opcode = code[i]; switch (opcode) { @@ -8207,7 +8204,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { break; default: #if MJS_ENABLE_DEBUG - mjs_dump(mjs, 1, stdout); + mjs_dump(mjs, 1); #endif mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "Unknown opcode: %d, off %d+%d", (int) opcode, (int) bp.start_idx, (int) i); @@ -8243,7 +8240,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, size_t off = mjs->bcode_len; mjs_val_t r = MJS_UNDEFINED; mjs->error = mjs_parse(path, src, mjs); - if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1, stderr); + if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1); if (generate_jsc == -1) generate_jsc = mjs->generate_jsc; if (mjs->error == MJS_OK) { #if MJS_GENERATE_JSC && defined(CS_MMAP) @@ -12687,7 +12684,7 @@ MJS_PRIVATE int pnext(struct pstate *p) { */ /* Amalgamated: #include "common/cs_varint.h" */ - +/* Amalgamated: #include "frozen/frozen.h" */ /* Amalgamated: #include "mjs/src/mjs_array.h" */ /* Amalgamated: #include "mjs/src/mjs_bcode.h" */ /* Amalgamated: #include "mjs/src/mjs_core.h" */ @@ -12727,44 +12724,54 @@ MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t) { } } -void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { +void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { if (mjs_is_number(v)) { double iv, d = mjs_get_double(mjs, v); if (modf(d, &iv) == 0) { - fprintf(fp, "%" INT64_FMT, (int64_t) d); + json_printf(out, "%" INT64_FMT, (int64_t) d); } else { - fprintf(fp, "%f", mjs_get_double(mjs, v)); + json_printf(out, "%f", mjs_get_double(mjs, v)); } } else if (mjs_is_boolean(v)) { - fprintf(fp, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); + json_printf(out, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); } else if (mjs_is_string(v)) { size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); for (i = 0; i < size; i++) { int ch = ((unsigned char *) s)[i]; if (isprint(ch)) { - putchar(ch); + json_printf(out, "%c", ch); } else { - printf("\\x%02x", ch); + json_printf(out, "\\x%02x", ch); } } } else if (mjs_is_array(v)) { - fprintf(fp, ""); + json_printf(out, ""); } else if (mjs_is_object(v)) { - fprintf(fp, ""); + json_printf(out, ""); } else if (mjs_is_foreign(v)) { - fprintf(fp, "", (unsigned long) mjs_get_ptr(mjs, v)); + json_printf(out, "", (unsigned long) mjs_get_ptr(mjs, v)); } else if (mjs_is_function(v)) { - fprintf(fp, "", (int) mjs_get_func_addr(v)); + json_printf(out, "", (int) mjs_get_func_addr(v)); } else if (mjs_is_null(v)) { - fprintf(fp, "null"); + json_printf(out, "null"); } else if (mjs_is_undefined(v)) { - fprintf(fp, "undefined"); + json_printf(out, "undefined"); } else { - fprintf(fp, "(unknown value type %" INT64_FMT ") ", (int64_t) v); + json_printf(out, "(unknown value type %" INT64_FMT ") ", (int64_t) v); } } +void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t n) { + struct json_out out = JSON_OUT_BUF(buf, n); + mjs_jprintf(v, mjs, &out); +} + +void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { + struct json_out out = JSON_OUT_FILE(fp); + mjs_jprintf(v, mjs, &out); +} + #if MJS_ENABLE_DEBUG MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { @@ -12777,41 +12784,44 @@ MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { "RETURN", "LOOP", "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", "ARGS", "FOR_IN_NEXT", }; - const char *name = "UNKNOWN OPCODE"; + const char *name = "???"; assert(ARRAY_SIZE(names) == OP_MAX); if (opcode < ARRAY_SIZE(names)) name = names[opcode]; return name; } -MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { +MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i) { + char buf[40]; size_t start_i = i; - fprintf(fp, "\t%-3u %-8s", (unsigned) i, opcodetostr(code[i])); + + snprintf(buf, sizeof(buf), "\t%-3u %-8s", (unsigned) i, opcodetostr(code[i])); switch (code[i]) { case OP_PUSH_FUNC: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, " %04u", (unsigned) (i - n)); + LOG(LL_VERBOSE_DEBUG, ("%s %04u", buf, (unsigned) (i - n))); i += llen; break; } case OP_PUSH_INT: { int llen; unsigned long n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t%lu", n); + LOG(LL_VERBOSE_DEBUG, ("%s\t%lu", buf, n)); i += llen; break; } case OP_SET_ARG: { int llen1, llen2, n, arg_no = cs_varint_decode(&code[i + 1], &llen1); n = cs_varint_decode(&code[i + llen1 + 1], &llen2); - fprintf(fp, "\t[%.*s] %d", n, code + i + 1 + llen1 + llen2, arg_no); + LOG(LL_VERBOSE_DEBUG, + ("%s\t[%.*s] %d", buf, n, code + i + 1 + llen1 + llen2, arg_no)); i += llen1 + llen2 + n; break; } case OP_PUSH_STR: case OP_PUSH_DBL: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t[%.*s]", n, code + i + 1 + llen); + LOG(LL_VERBOSE_DEBUG, ("%s\t[%.*s]", buf, n, code + i + 1 + llen)); i += llen + n; break; } @@ -12821,18 +12831,20 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { case OP_JMP_FALSE: case OP_JMP_NEUTRAL_FALSE: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t%u", - (unsigned) i + n + llen + - 1 /* becaue i will be incremented on the usual terms */); + LOG(LL_VERBOSE_DEBUG, + ("%s\t%u", buf, + (unsigned) i + n + llen + + 1 /* becaue i will be incremented on the usual terms */)); i += llen; break; } case OP_LOOP: { int l1, l2, n2, n1 = cs_varint_decode(&code[i + 1], &l1); n2 = cs_varint_decode(&code[i + l1 + 1], &l2); - fprintf(fp, "\tB:%lu C:%lu (%d)", - (unsigned long) i + 1 /* OP_LOOP */ + l1 + n1, - (unsigned long) i + 1 /* OP_LOOP */ + l1 + l2 + n2, (int) i); + LOG(LL_VERBOSE_DEBUG, + ("%s\tB:%lu C:%lu (%d)", buf, + (unsigned long) i + 1 /* OP_LOOP */ + l1 + n1, + (unsigned long) i + 1 /* OP_LOOP */ + l1 + l2 + n2, (int) i)); i += l1 + l2; break; } @@ -12886,7 +12898,7 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { case TOK_URSHIFT_ASSIGN: name = ">>>="; break; } /* clang-format on */ - fprintf(fp, "\t%s", name); + LOG(LL_VERBOSE_DEBUG, ("%s\t%s", buf, name)); i++; break; } @@ -12899,24 +12911,22 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { &code[i + 1 + MJS_HDR_ITEM_MAP_OFFSET * sizeof(total_size)], sizeof(map_offset)); i += sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT; - fprintf(fp, "\t[%s] end:%lu map_offset: %lu", &code[i + 1], - (unsigned long) start + total_size, - (unsigned long) start + map_offset); + LOG(LL_VERBOSE_DEBUG, ("%s\t[%s] end:%lu map_offset: %lu", buf, + &code[i + 1], (unsigned long) start + total_size, + (unsigned long) start + map_offset)); i += strlen((char *) (code + i + 1)) + 1; break; } } - - fputc('\n', fp); return i - start_i; } -void mjs_disasm(const uint8_t *code, size_t len, FILE *fp) { +void mjs_disasm(const uint8_t *code, size_t len) { size_t i, start = 0; mjs_header_item_t map_offset = 0, total_size = 0; for (i = 0; i < len; i++) { - size_t delta = mjs_disasm_single(code, i, fp); + size_t delta = mjs_disasm_single(code, i); if (code[i] == OP_BCODE_HEADER) { start = i; memcpy(&total_size, &code[i + 1], sizeof(total_size)); @@ -12935,35 +12945,34 @@ void mjs_disasm(const uint8_t *code, size_t len, FILE *fp) { } static void mjs_dump_obj_stack(const char *name, const struct mbuf *m, - struct mjs *mjs, FILE *fp) { + struct mjs *mjs) { + char buf[50]; size_t i, n; n = mjs_stack_size(m); - fprintf(fp, " %12s (%d elems): ", name, (int) n); + LOG(LL_VERBOSE_DEBUG, ("%12s (%d elems): ", name, (int) n)); for (i = 0; i < n; i++) { - fprintf(fp, " ["); - mjs_fprintf(((mjs_val_t *) m->buf)[i], mjs, fp); - fprintf(fp, "]"); + mjs_sprintf(((mjs_val_t *) m->buf)[i], mjs, buf, sizeof(buf)); + LOG(LL_VERBOSE_DEBUG, ("%34s", buf)); } - fprintf(fp, "\n"); } -void mjs_dump(struct mjs *mjs, int do_disasm, FILE *fp) { - fprintf(fp, "------- MJS VM DUMP BEGIN\n"); - mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs, fp); - mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs, fp); - mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs, fp); - mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs, fp); - mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs, fp); +void mjs_dump(struct mjs *mjs, int do_disasm) { + LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP BEGIN")); + mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs); + mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs); + mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs); + mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs); + mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs); if (do_disasm) { int parts_cnt = mjs_bcode_parts_cnt(mjs); int i; - fprintf(fp, " CODE:\n"); + LOG(LL_VERBOSE_DEBUG, ("%23s", "CODE:")); for (i = 0; i < parts_cnt; i++) { struct mjs_bcode_part *bp = mjs_bcode_part_get(mjs, i); - mjs_disasm((uint8_t *) bp->data.p, bp->data.len, fp); + mjs_disasm((uint8_t *) bp->data.p, bp->data.len); } } - fprintf(fp, "------- MJS VM DUMP END\n"); + LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP END")); } MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, diff --git a/mjs.h b/mjs.h index 88db6e7..2adbce4 100644 --- a/mjs.h +++ b/mjs.h @@ -896,11 +896,12 @@ extern "C" { const char *mjs_typeof(mjs_val_t v); void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp); +void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t buflen); #if MJS_ENABLE_DEBUG -void mjs_disasm(const uint8_t *code, size_t len, FILE *fp); -void mjs_dump(struct mjs *mjs, int do_disasm, FILE *fp); +void mjs_disasm(const uint8_t *code, size_t len); +void mjs_dump(struct mjs *mjs, int do_disasm); #endif diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index f7765e9..be7b626 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -515,11 +515,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { #endif const uint8_t *code = (const uint8_t *) bp.data.p; - if (cs_log_threshold >= LL_VERBOSE_DEBUG) { - /* mjs_dump(mjs, 0, stdout); */ - printf("executing: "); - mjs_disasm_single(code, i, stdout); - } + mjs_disasm_single(code, i); prev_opcode = opcode; opcode = code[i]; switch (opcode) { @@ -873,7 +869,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { break; default: #if MJS_ENABLE_DEBUG - mjs_dump(mjs, 1, stdout); + mjs_dump(mjs, 1); #endif mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "Unknown opcode: %d, off %d+%d", (int) opcode, (int) bp.start_idx, (int) i); @@ -909,7 +905,7 @@ MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path, size_t off = mjs->bcode_len; mjs_val_t r = MJS_UNDEFINED; mjs->error = mjs_parse(path, src, mjs); - if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1, stderr); + if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1); if (generate_jsc == -1) generate_jsc = mjs->generate_jsc; if (mjs->error == MJS_OK) { #if MJS_GENERATE_JSC && defined(CS_MMAP) diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index 15d7dcd..1103e49 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -4,7 +4,7 @@ */ #include "common/cs_varint.h" - +#include "frozen/frozen.h" #include "mjs/src/mjs_array.h" #include "mjs/src/mjs_bcode.h" #include "mjs/src/mjs_core.h" @@ -44,44 +44,54 @@ MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t) { } } -void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { +void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { if (mjs_is_number(v)) { double iv, d = mjs_get_double(mjs, v); if (modf(d, &iv) == 0) { - fprintf(fp, "%" INT64_FMT, (int64_t) d); + json_printf(out, "%" INT64_FMT, (int64_t) d); } else { - fprintf(fp, "%f", mjs_get_double(mjs, v)); + json_printf(out, "%f", mjs_get_double(mjs, v)); } } else if (mjs_is_boolean(v)) { - fprintf(fp, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); + json_printf(out, "%s", mjs_get_bool(mjs, v) ? "true" : "false"); } else if (mjs_is_string(v)) { size_t i, size; const char *s = mjs_get_string(mjs, &v, &size); for (i = 0; i < size; i++) { int ch = ((unsigned char *) s)[i]; if (isprint(ch)) { - putchar(ch); + json_printf(out, "%c", ch); } else { - printf("\\x%02x", ch); + json_printf(out, "\\x%02x", ch); } } } else if (mjs_is_array(v)) { - fprintf(fp, ""); + json_printf(out, ""); } else if (mjs_is_object(v)) { - fprintf(fp, ""); + json_printf(out, ""); } else if (mjs_is_foreign(v)) { - fprintf(fp, "", (unsigned long) mjs_get_ptr(mjs, v)); + json_printf(out, "", (unsigned long) mjs_get_ptr(mjs, v)); } else if (mjs_is_function(v)) { - fprintf(fp, "", (int) mjs_get_func_addr(v)); + json_printf(out, "", (int) mjs_get_func_addr(v)); } else if (mjs_is_null(v)) { - fprintf(fp, "null"); + json_printf(out, "null"); } else if (mjs_is_undefined(v)) { - fprintf(fp, "undefined"); + json_printf(out, "undefined"); } else { - fprintf(fp, "(unknown value type %" INT64_FMT ") ", (int64_t) v); + json_printf(out, "(unknown value type %" INT64_FMT ") ", (int64_t) v); } } +void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t n) { + struct json_out out = JSON_OUT_BUF(buf, n); + mjs_jprintf(v, mjs, &out); +} + +void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) { + struct json_out out = JSON_OUT_FILE(fp); + mjs_jprintf(v, mjs, &out); +} + #if MJS_ENABLE_DEBUG MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { @@ -94,41 +104,44 @@ MJS_PRIVATE const char *opcodetostr(uint8_t opcode) { "RETURN", "LOOP", "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR", "ARGS", "FOR_IN_NEXT", }; - const char *name = "UNKNOWN OPCODE"; + const char *name = "???"; assert(ARRAY_SIZE(names) == OP_MAX); if (opcode < ARRAY_SIZE(names)) name = names[opcode]; return name; } -MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { +MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i) { + char buf[40]; size_t start_i = i; - fprintf(fp, "\t%-3u %-8s", (unsigned) i, opcodetostr(code[i])); + + snprintf(buf, sizeof(buf), "\t%-3u %-8s", (unsigned) i, opcodetostr(code[i])); switch (code[i]) { case OP_PUSH_FUNC: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, " %04u", (unsigned) (i - n)); + LOG(LL_VERBOSE_DEBUG, ("%s %04u", buf, (unsigned) (i - n))); i += llen; break; } case OP_PUSH_INT: { int llen; unsigned long n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t%lu", n); + LOG(LL_VERBOSE_DEBUG, ("%s\t%lu", buf, n)); i += llen; break; } case OP_SET_ARG: { int llen1, llen2, n, arg_no = cs_varint_decode(&code[i + 1], &llen1); n = cs_varint_decode(&code[i + llen1 + 1], &llen2); - fprintf(fp, "\t[%.*s] %d", n, code + i + 1 + llen1 + llen2, arg_no); + LOG(LL_VERBOSE_DEBUG, + ("%s\t[%.*s] %d", buf, n, code + i + 1 + llen1 + llen2, arg_no)); i += llen1 + llen2 + n; break; } case OP_PUSH_STR: case OP_PUSH_DBL: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t[%.*s]", n, code + i + 1 + llen); + LOG(LL_VERBOSE_DEBUG, ("%s\t[%.*s]", buf, n, code + i + 1 + llen)); i += llen + n; break; } @@ -138,18 +151,20 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { case OP_JMP_FALSE: case OP_JMP_NEUTRAL_FALSE: { int llen, n = cs_varint_decode(&code[i + 1], &llen); - fprintf(fp, "\t%u", - (unsigned) i + n + llen + - 1 /* becaue i will be incremented on the usual terms */); + LOG(LL_VERBOSE_DEBUG, + ("%s\t%u", buf, + (unsigned) i + n + llen + + 1 /* becaue i will be incremented on the usual terms */)); i += llen; break; } case OP_LOOP: { int l1, l2, n2, n1 = cs_varint_decode(&code[i + 1], &l1); n2 = cs_varint_decode(&code[i + l1 + 1], &l2); - fprintf(fp, "\tB:%lu C:%lu (%d)", - (unsigned long) i + 1 /* OP_LOOP */ + l1 + n1, - (unsigned long) i + 1 /* OP_LOOP */ + l1 + l2 + n2, (int) i); + LOG(LL_VERBOSE_DEBUG, + ("%s\tB:%lu C:%lu (%d)", buf, + (unsigned long) i + 1 /* OP_LOOP */ + l1 + n1, + (unsigned long) i + 1 /* OP_LOOP */ + l1 + l2 + n2, (int) i)); i += l1 + l2; break; } @@ -203,7 +218,7 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { case TOK_URSHIFT_ASSIGN: name = ">>>="; break; } /* clang-format on */ - fprintf(fp, "\t%s", name); + LOG(LL_VERBOSE_DEBUG, ("%s\t%s", buf, name)); i++; break; } @@ -216,24 +231,22 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp) { &code[i + 1 + MJS_HDR_ITEM_MAP_OFFSET * sizeof(total_size)], sizeof(map_offset)); i += sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT; - fprintf(fp, "\t[%s] end:%lu map_offset: %lu", &code[i + 1], - (unsigned long) start + total_size, - (unsigned long) start + map_offset); + LOG(LL_VERBOSE_DEBUG, ("%s\t[%s] end:%lu map_offset: %lu", buf, + &code[i + 1], (unsigned long) start + total_size, + (unsigned long) start + map_offset)); i += strlen((char *) (code + i + 1)) + 1; break; } } - - fputc('\n', fp); return i - start_i; } -void mjs_disasm(const uint8_t *code, size_t len, FILE *fp) { +void mjs_disasm(const uint8_t *code, size_t len) { size_t i, start = 0; mjs_header_item_t map_offset = 0, total_size = 0; for (i = 0; i < len; i++) { - size_t delta = mjs_disasm_single(code, i, fp); + size_t delta = mjs_disasm_single(code, i); if (code[i] == OP_BCODE_HEADER) { start = i; memcpy(&total_size, &code[i + 1], sizeof(total_size)); @@ -252,35 +265,34 @@ void mjs_disasm(const uint8_t *code, size_t len, FILE *fp) { } static void mjs_dump_obj_stack(const char *name, const struct mbuf *m, - struct mjs *mjs, FILE *fp) { + struct mjs *mjs) { + char buf[50]; size_t i, n; n = mjs_stack_size(m); - fprintf(fp, " %12s (%d elems): ", name, (int) n); + LOG(LL_VERBOSE_DEBUG, ("%12s (%d elems): ", name, (int) n)); for (i = 0; i < n; i++) { - fprintf(fp, " ["); - mjs_fprintf(((mjs_val_t *) m->buf)[i], mjs, fp); - fprintf(fp, "]"); + mjs_sprintf(((mjs_val_t *) m->buf)[i], mjs, buf, sizeof(buf)); + LOG(LL_VERBOSE_DEBUG, ("%34s", buf)); } - fprintf(fp, "\n"); } -void mjs_dump(struct mjs *mjs, int do_disasm, FILE *fp) { - fprintf(fp, "------- MJS VM DUMP BEGIN\n"); - mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs, fp); - mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs, fp); - mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs, fp); - mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs, fp); - mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs, fp); +void mjs_dump(struct mjs *mjs, int do_disasm) { + LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP BEGIN")); + mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs); + mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs); + mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs); + mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs); + mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs); if (do_disasm) { int parts_cnt = mjs_bcode_parts_cnt(mjs); int i; - fprintf(fp, " CODE:\n"); + LOG(LL_VERBOSE_DEBUG, ("%23s", "CODE:")); for (i = 0; i < parts_cnt; i++) { struct mjs_bcode_part *bp = mjs_bcode_part_get(mjs, i); - mjs_disasm((uint8_t *) bp->data.p, bp->data.len, fp); + mjs_disasm((uint8_t *) bp->data.p, bp->data.len); } } - fprintf(fp, "------- MJS VM DUMP END\n"); + LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP END")); } MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, diff --git a/mjs/src/mjs_util.h b/mjs/src/mjs_util.h index e599731..7125eee 100644 --- a/mjs/src/mjs_util.h +++ b/mjs/src/mjs_util.h @@ -16,7 +16,7 @@ extern "C" { struct mjs_bcode_part; MJS_PRIVATE const char *opcodetostr(uint8_t opcode); -MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i, FILE *fp); +MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i); MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t); /* diff --git a/mjs/src/mjs_util_public.h b/mjs/src/mjs_util_public.h index a79e140..7fdd78e 100644 --- a/mjs/src/mjs_util_public.h +++ b/mjs/src/mjs_util_public.h @@ -16,11 +16,12 @@ extern "C" { const char *mjs_typeof(mjs_val_t v); void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp); +void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t buflen); #if MJS_ENABLE_DEBUG -void mjs_disasm(const uint8_t *code, size_t len, FILE *fp); -void mjs_dump(struct mjs *mjs, int do_disasm, FILE *fp); +void mjs_disasm(const uint8_t *code, size_t len); +void mjs_dump(struct mjs *mjs, int do_disasm); #endif From 3da47e81d86a1edf04f3fb179ae5520d61c87752 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jun 2017 17:59:36 +0300 Subject: [PATCH 042/265] Support %x in json_printf PUBLISHED_FROM=27e71828015e381f94169caf9f9f01722c343f87 --- frozen/frozen.c | 3 ++- mjs.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 1606d1d..6ce03a1 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -630,7 +630,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { * TODO(dfrank): reimplement %s and %.*s in order to avoid that. */ - const char *end_of_format_specifier = "sdfFgGlhuIc.*-0123456789"; + const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789"; size_t n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; size_t need_len; @@ -706,6 +706,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { } len += out->printer(out, quote, 1); } else { + len += out->printer(out, fmt, 1); fmt++; } } diff --git a/mjs.c b/mjs.c index 2f71404..0cf05f9 100644 --- a/mjs.c +++ b/mjs.c @@ -5632,7 +5632,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { * TODO(dfrank): reimplement %s and %.*s in order to avoid that. */ - const char *end_of_format_specifier = "sdfFgGlhuIc.*-0123456789"; + const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789"; size_t n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; size_t need_len; @@ -5708,6 +5708,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { } len += out->printer(out, quote, 1); } else { + len += out->printer(out, fmt, 1); fmt++; } } From 3e70a3077fd0bb3e70076c94353e8486f3199168 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jun 2017 16:05:17 +0100 Subject: [PATCH 043/265] Strip timestamps from the coredump log PUBLISHED_FROM=4abb6369fe751ac2b5206ab4b537454dd5a38c0a --- common/platforms/esp/serve_core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/platforms/esp/serve_core.py b/common/platforms/esp/serve_core.py index adc0526..2ff0d0e 100755 --- a/common/platforms/esp/serve_core.py +++ b/common/platforms/esp/serve_core.py @@ -21,6 +21,7 @@ import ctypes import json import os +import re import struct import sys @@ -126,7 +127,8 @@ def _read(self, filename): print >>sys.stderr, "Found core at %d - %d" % (start_pos, end_pos) f.seek(start_pos) core_json = f.read(end_pos - start_pos) - return json.loads(core_json.replace('\n', '').replace('\r', '')) + stripped = re.sub(r'(?im)\s+(\[.{1,40}\])?\s*', '', core_json) + return json.loads(stripped) def _map_core(self, core): mem = [] From a1e0fcb2c4f13eff8f5ca44291d4c54a0d43e22a Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jun 2017 18:25:36 +0300 Subject: [PATCH 044/265] Fix mjs_jprintf() PUBLISHED_FROM=ac47a7779a25f0be940bd7bef169c18a793b9122 --- frozen/frozen.c | 7 ++++--- mjs.c | 24 +++++++++++++----------- mjs/src/mjs_util.c | 17 +++++++++-------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 6ce03a1..735989d 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -752,7 +752,8 @@ int json_printf_array(struct json_out *out, va_list *ap) { } #ifdef _WIN32 -int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) WEAK; +int cs_win_vsnprintf(char *str, size_t size, const char *format, + va_list ap) WEAK; int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int res = _vsnprintf(str, size, format, ap); va_end(ap); @@ -859,7 +860,7 @@ static void json_scanf_cb(void *callback_data, const char *name, size_t name_len, const char *path, const struct json_token *token) { struct json_scanf_info *info = (struct json_scanf_info *) callback_data; - char buf[32]; /* Must be enough to hold numbers */ + char buf[32]; /* Must be enough to hold numbers */ (void) name; (void) name_len; @@ -880,7 +881,7 @@ static void json_scanf_cb(void *callback_data, const char *name, switch (info->type) { case 'B': info->num_conversions++; - switch (sizeof(bool)){ + switch (sizeof(bool)) { case sizeof(char): *(char *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0); break; diff --git a/mjs.c b/mjs.c index 0cf05f9..05aac3a 100644 --- a/mjs.c +++ b/mjs.c @@ -5754,7 +5754,8 @@ int json_printf_array(struct json_out *out, va_list *ap) { } #ifdef _WIN32 -int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) WEAK; +int cs_win_vsnprintf(char *str, size_t size, const char *format, + va_list ap) WEAK; int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int res = _vsnprintf(str, size, format, ap); va_end(ap); @@ -5861,7 +5862,7 @@ static void json_scanf_cb(void *callback_data, const char *name, size_t name_len, const char *path, const struct json_token *token) { struct json_scanf_info *info = (struct json_scanf_info *) callback_data; - char buf[32]; /* Must be enough to hold numbers */ + char buf[32]; /* Must be enough to hold numbers */ (void) name; (void) name_len; @@ -5882,7 +5883,7 @@ static void json_scanf_cb(void *callback_data, const char *name, switch (info->type) { case 'B': info->num_conversions++; - switch (sizeof(bool)){ + switch (sizeof(bool)) { case sizeof(char): *(char *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0); break; @@ -12743,23 +12744,24 @@ void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { if (isprint(ch)) { json_printf(out, "%c", ch); } else { - json_printf(out, "\\x%02x", ch); + json_printf(out, "%s%02x", "\\x", ch); } } } else if (mjs_is_array(v)) { - json_printf(out, ""); + json_printf(out, "%s", ""); } else if (mjs_is_object(v)) { - json_printf(out, ""); + json_printf(out, "%s", ""); } else if (mjs_is_foreign(v)) { - json_printf(out, "", (unsigned long) mjs_get_ptr(mjs, v)); + json_printf(out, "%s%lx%s", ""); } else if (mjs_is_function(v)) { - json_printf(out, "", (int) mjs_get_func_addr(v)); + json_printf(out, "%s%d%s", ""); } else if (mjs_is_null(v)) { - json_printf(out, "null"); + json_printf(out, "%s", "null"); } else if (mjs_is_undefined(v)) { - json_printf(out, "undefined"); + json_printf(out, "%s", "undefined"); } else { - json_printf(out, "(unknown value type %" INT64_FMT ") ", (int64_t) v); + json_printf(out, "%s%" INT64_FMT "%s", ""); } } diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index 1103e49..85c9309 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -62,23 +62,24 @@ void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { if (isprint(ch)) { json_printf(out, "%c", ch); } else { - json_printf(out, "\\x%02x", ch); + json_printf(out, "%s%02x", "\\x", ch); } } } else if (mjs_is_array(v)) { - json_printf(out, ""); + json_printf(out, "%s", ""); } else if (mjs_is_object(v)) { - json_printf(out, ""); + json_printf(out, "%s", ""); } else if (mjs_is_foreign(v)) { - json_printf(out, "", (unsigned long) mjs_get_ptr(mjs, v)); + json_printf(out, "%s%lx%s", ""); } else if (mjs_is_function(v)) { - json_printf(out, "", (int) mjs_get_func_addr(v)); + json_printf(out, "%s%d%s", ""); } else if (mjs_is_null(v)) { - json_printf(out, "null"); + json_printf(out, "%s", "null"); } else if (mjs_is_undefined(v)) { - json_printf(out, "undefined"); + json_printf(out, "%s", "undefined"); } else { - json_printf(out, "(unknown value type %" INT64_FMT ") ", (int64_t) v); + json_printf(out, "%s%" INT64_FMT "%s", ""); } } From 8cda679fe3b3652baa7336aa3162305271639913 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 1 Jul 2017 09:47:33 +0100 Subject: [PATCH 045/265] Clean up v7 from mongoose PUBLISHED_FROM=efa9cc3aaf0c5ae8841e029370f882b615cebf1b --- common/cs_dbg.c | 2 +- mjs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/cs_dbg.c b/common/cs_dbg.c index 33a7632..dab6f90 100644 --- a/common/cs_dbg.c +++ b/common/cs_dbg.c @@ -42,7 +42,7 @@ void cs_log_set_filter(char *str) { s_filter_pattern = NULL; s_filter_pattern_len = 0; } -}; +} int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; int cs_log_print_prefix(enum cs_log_level level, const char *func, diff --git a/mjs.c b/mjs.c index 05aac3a..e53a6fb 100644 --- a/mjs.c +++ b/mjs.c @@ -4217,7 +4217,7 @@ void cs_log_set_filter(char *str) { s_filter_pattern = NULL; s_filter_pattern_len = 0; } -}; +} int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; int cs_log_print_prefix(enum cs_log_level level, const char *func, From 5e2bad23c09ee09babb3d6016b8d462265468328 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 2 Jul 2017 14:46:02 +0300 Subject: [PATCH 046/265] Use -MP gcc flag for esp8266 It helps to work around the issue with phantom `.d` files left after removing the header. ``` -MP This option instructs CPP to add a phony target for each dependency other than the main file, causing each to depend on nothing. These dummy rules work around errors make gives if you remove header files without updating the Makefile to match. This is typical output: test.o: test.c test.h test.h: ``` PUBLISHED_FROM=3260f5515e7d72334fa851cd8c3a0ed15c38c79f --- common/platforms/esp8266/common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/platforms/esp8266/common.mk b/common/platforms/esp8266/common.mk index fe2a31c..5345221 100644 --- a/common/platforms/esp8266/common.mk +++ b/common/platforms/esp8266/common.mk @@ -26,7 +26,7 @@ endef define compile_params $(vecho) "$5 $1 -> $2" -$(Q) $(CC_WRAPPER) $3 -MD $(INCDIRS) $4 -c $1 -o $2 +$(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2 endef define compile From 07f2e42763d9144af1ef72f261ed0da0929e5657 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 3 Jul 2017 17:55:24 +0300 Subject: [PATCH 047/265] Add mg_strchr Write unit tests for some mg_str functions. PUBLISHED_FROM=1fc7e1d5d5ef259d4023f295aec8651caa3e7e86 --- mjs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mjs.c b/mjs.c index e53a6fb..00c8274 100644 --- a/mjs.c +++ b/mjs.c @@ -1540,6 +1540,11 @@ struct mg_str mg_strdup(const struct mg_str s); */ struct mg_str mg_strdup_nul(const struct mg_str s); +/* + * Locates character in a string. + */ +const char *mg_strchr(const struct mg_str s, int c); + int mg_strcmp(const struct mg_str str1, const struct mg_str str2); int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); From 23ca3773ec92dbe51d8683f0c083d9cf085ed9a3 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 4 Jul 2017 19:49:52 +0100 Subject: [PATCH 048/265] Add JS net api test PUBLISHED_FROM=f2821b104f8f2fc196ce4064b7c9f35ea152368d --- common/platforms/lwip/mg_lwip_net_if.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index c5bd2ea..7b69b8e 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -577,17 +577,20 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, } struct udp_pcb *upcb = cs->pcb.udp; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - ip_addr_t *ip = (ip_addr_t *) &nc->sa.sin.sin_addr.s_addr; +#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 + ip_addr_t ip = { .u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0 }; +#else + ip_addr_t ip = { .addr = nc->sa.sin.sin_addr.s_addr }; +#endif u16_t port = ntohs(nc->sa.sin.sin_port); if (p == NULL) { DBG(("OOM")); return 0; } memcpy(p->payload, data, len); - struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = ip, .port = port}; + struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port}; tcpip_callback(udp_sendto_tcpip, &ctx); cs->err = ctx.ret; - DBG(("%p udp_sendto = %d", nc, cs->err)); pbuf_free(p); return (cs->err == ERR_OK ? len : -1); } From 422ca2706b4a334584341c2fc7e4c6f125280f69 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 4 Jul 2017 22:31:26 +0300 Subject: [PATCH 049/265] Fix formatting PUBLISHED_FROM=4d4d49136e13ba8035d452a4f64fcaf48f15bdb3 --- common/platforms/lwip/mg_lwip_net_if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 7b69b8e..c33e37b 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -578,9 +578,9 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, struct udp_pcb *upcb = cs->pcb.udp; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 - ip_addr_t ip = { .u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0 }; + ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0}; #else - ip_addr_t ip = { .addr = nc->sa.sin.sin_addr.s_addr }; + ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr}; #endif u16_t port = ntohs(nc->sa.sin.sin_port); if (p == NULL) { From 035f8e65feeaa800e596dec02bfa9a695643e857 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 5 Jul 2017 17:14:34 +0100 Subject: [PATCH 050/265] Add mg_strstr PUBLISHED_FROM=4306e870e2cab854febb6becc198ca2247e2e002 --- mjs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mjs.c b/mjs.c index 00c8274..590a133 100644 --- a/mjs.c +++ b/mjs.c @@ -1548,6 +1548,8 @@ const char *mg_strchr(const struct mg_str s, int c); int mg_strcmp(const struct mg_str str1, const struct mg_str str2); int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); +const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); + #ifdef __cplusplus } #endif /* __cplusplus */ From 66d55f5f043321a1668cdb1df1f35ef6f36b2574 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 10 Jul 2017 19:53:49 +0100 Subject: [PATCH 051/265] ESP8266 SDK 2.1.0 update PUBLISHED_FROM=d5b16c28bb6689c32b7627fcb7f7af9c96f9725c --- common/platforms/esp8266/esp_missing_includes.h | 8 -------- common/platforms/esp8266/rboot/rboot/rboot-private.h | 4 ---- 2 files changed, 12 deletions(-) diff --git a/common/platforms/esp8266/esp_missing_includes.h b/common/platforms/esp8266/esp_missing_includes.h index 0e90630..fc7d69f 100644 --- a/common/platforms/esp8266/esp_missing_includes.h +++ b/common/platforms/esp8266/esp_missing_includes.h @@ -15,8 +15,6 @@ void pp_soft_wdt_feed(void); void pp_soft_wdt_restart(void); void system_soft_wdt_stop(void); /* Alias for pp_soft_wdt_stop */ -void uart_div_modify(int no, unsigned int freq); - void Cache_Read_Disable(void); void Cache_Read_Enable(uint32_t, uint32_t, uint32_t); void Cache_Read_Disable_2(void); @@ -31,14 +29,8 @@ uint32_t SPIRead(uint32_t addr, void *dst, uint32_t size); #include /* There are no declarations for these anywhere in the SDK (as of 1.2.0). */ -void ets_install_putc1(void *routine); -void ets_isr_attach(int intr, void *handler, void *arg); void ets_isr_mask(unsigned intr); void ets_isr_unmask(unsigned intr); -void ets_timer_arm_new(ETSTimer *a, int b, int c, int isMstimer); -void ets_timer_disarm(ETSTimer *a); -void ets_timer_setfn(ETSTimer *t, ETSTimerFunc *fn, void *parg); -void ets_delay_us(unsigned us); void system_restart_local(void); int os_printf_plus(const char *format, ...); diff --git a/common/platforms/esp8266/rboot/rboot/rboot-private.h b/common/platforms/esp8266/rboot/rboot/rboot-private.h index 6733d64..5b4d52f 100644 --- a/common/platforms/esp8266/rboot/rboot/rboot-private.h +++ b/common/platforms/esp8266/rboot/rboot/rboot-private.h @@ -32,14 +32,10 @@ typedef unsigned char uint8; #define BUFFER_SIZE 0x100 // esp8266 built in rom functions -extern void ets_delay_us(unsigned); -extern void ets_memcpy(void*, const void*, uint32); -extern void ets_memset(void*, uint8, uint32); extern void ets_printf(const char*, ...); extern uint32 SPIRead(uint32 addr, void *outptr, uint32 len); extern uint32 SPIEraseSector(int); extern uint32 SPIWrite(uint32 addr, void *inptr, uint32 len); -extern void uart_div_modify(int no, unsigned int freq); // functions we'll call by address typedef void stage2a(uint32); From b1b20173090579d13fca0826978085bbe24dd646 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 11 Jul 2017 11:09:00 +0300 Subject: [PATCH 052/265] Add support for ffi-ed callbacks with double args PUBLISHED_FROM=ca67da70e11f2578e8cffdcf1754339f60a11607 --- mjs.c | 69 +++++++++++++++++++++++++++++++------------ mjs/src/mjs_ffi.c | 69 +++++++++++++++++++++++++++++++------------ mjs/tests/unit_test.c | 4 +-- 3 files changed, 102 insertions(+), 40 deletions(-) diff --git a/mjs.c b/mjs.c index 590a133..e489c87 100644 --- a/mjs.c +++ b/mjs.c @@ -8839,6 +8839,26 @@ static uintptr_t ffi_cb_impl_wwwwwwp(uintptr_t w0, uintptr_t w1, uintptr_t w2, ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5); return ffi_cb_impl_generic((void *) w5, &data).w; } + +static uintptr_t ffi_cb_impl_wpd(uintptr_t w0, double d1) { + struct ffi_cb_data data; + + memset(&data, 0, sizeof(data)); + data.args[0].w = w0; + data.args[1].d = d1; + + return ffi_cb_impl_generic((void *) w0, &data).w; +} + +static uintptr_t ffi_cb_impl_wdp(double d0, uintptr_t w1) { + struct ffi_cb_data data; + + memset(&data, 0, sizeof(data)); + data.args[0].d = d0; + data.args[1].w = w1; + + return ffi_cb_impl_generic((void *) w1, &data).w; +} /* }}} */ static struct mjs_ffi_cb_args **ffi_get_matching(struct mjs_ffi_cb_args **plist, @@ -8879,25 +8899,36 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { if (sig->args_cnt <= MJS_CB_ARGS_MAX_CNT) { if (mjs_ffi_is_regular_word_or_void(sig->val_types[0])) { /* Return type is a word or void */ - if (double_cnt == 0) { - /* No double arguments */ - switch (userdata_idx) { - case 1: - return (ffi_fn_t *) ffi_cb_impl_wpwwwww; - case 2: - return (ffi_fn_t *) ffi_cb_impl_wwpwwww; - case 3: - return (ffi_fn_t *) ffi_cb_impl_wwwpwww; - case 4: - return (ffi_fn_t *) ffi_cb_impl_wwwwpww; - case 5: - return (ffi_fn_t *) ffi_cb_impl_wwwwwpw; - case 6: - return (ffi_fn_t *) ffi_cb_impl_wwwwwwp; - default: - /* should never be here */ - abort(); - } + switch (double_cnt) { + case 0: + /* No double arguments */ + switch (userdata_idx) { + case 1: + return (ffi_fn_t *) ffi_cb_impl_wpwwwww; + case 2: + return (ffi_fn_t *) ffi_cb_impl_wwpwwww; + case 3: + return (ffi_fn_t *) ffi_cb_impl_wwwpwww; + case 4: + return (ffi_fn_t *) ffi_cb_impl_wwwwpww; + case 5: + return (ffi_fn_t *) ffi_cb_impl_wwwwwpw; + case 6: + return (ffi_fn_t *) ffi_cb_impl_wwwwwwp; + default: + /* should never be here */ + abort(); + } + break; + case 1: + /* 1 double argument */ + switch (userdata_idx) { + case 1: + return (ffi_fn_t *) ffi_cb_impl_wpd; + case 2: + return (ffi_fn_t *) ffi_cb_impl_wdp; + } + break; } } } else { diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index 8494684..457b721 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -419,6 +419,26 @@ static uintptr_t ffi_cb_impl_wwwwwwp(uintptr_t w0, uintptr_t w1, uintptr_t w2, ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5); return ffi_cb_impl_generic((void *) w5, &data).w; } + +static uintptr_t ffi_cb_impl_wpd(uintptr_t w0, double d1) { + struct ffi_cb_data data; + + memset(&data, 0, sizeof(data)); + data.args[0].w = w0; + data.args[1].d = d1; + + return ffi_cb_impl_generic((void *) w0, &data).w; +} + +static uintptr_t ffi_cb_impl_wdp(double d0, uintptr_t w1) { + struct ffi_cb_data data; + + memset(&data, 0, sizeof(data)); + data.args[0].d = d0; + data.args[1].w = w1; + + return ffi_cb_impl_generic((void *) w1, &data).w; +} /* }}} */ static struct mjs_ffi_cb_args **ffi_get_matching(struct mjs_ffi_cb_args **plist, @@ -459,25 +479,36 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { if (sig->args_cnt <= MJS_CB_ARGS_MAX_CNT) { if (mjs_ffi_is_regular_word_or_void(sig->val_types[0])) { /* Return type is a word or void */ - if (double_cnt == 0) { - /* No double arguments */ - switch (userdata_idx) { - case 1: - return (ffi_fn_t *) ffi_cb_impl_wpwwwww; - case 2: - return (ffi_fn_t *) ffi_cb_impl_wwpwwww; - case 3: - return (ffi_fn_t *) ffi_cb_impl_wwwpwww; - case 4: - return (ffi_fn_t *) ffi_cb_impl_wwwwpww; - case 5: - return (ffi_fn_t *) ffi_cb_impl_wwwwwpw; - case 6: - return (ffi_fn_t *) ffi_cb_impl_wwwwwwp; - default: - /* should never be here */ - abort(); - } + switch (double_cnt) { + case 0: + /* No double arguments */ + switch (userdata_idx) { + case 1: + return (ffi_fn_t *) ffi_cb_impl_wpwwwww; + case 2: + return (ffi_fn_t *) ffi_cb_impl_wwpwwww; + case 3: + return (ffi_fn_t *) ffi_cb_impl_wwwpwww; + case 4: + return (ffi_fn_t *) ffi_cb_impl_wwwwpww; + case 5: + return (ffi_fn_t *) ffi_cb_impl_wwwwwpw; + case 6: + return (ffi_fn_t *) ffi_cb_impl_wwwwwwp; + default: + /* should never be here */ + abort(); + } + break; + case 1: + /* 1 double argument */ + switch (userdata_idx) { + case 1: + return (ffi_fn_t *) ffi_cb_impl_wpd; + case 2: + return (ffi_fn_t *) ffi_cb_impl_wdp; + } + break; } } } else { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index e60805a..06b4406 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -917,8 +917,8 @@ const char *test_parse_ffi_signature(struct mjs *mjs) { /* wrong signature: callback with double arg */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( - mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, void(*)(double, userdata), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, void(*)(double, userdata), userdata)\": bad ffi signature: \"void(*)(double, userdata)\": the callback signature is valid, but there's no existing callback implementation for it"); + mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, void(*)(double, double, userdata), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); + ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, void(*)(double, double, userdata), userdata)\": bad ffi signature: \"void(*)(double, double, userdata)\": the callback signature is valid, but there's no existing callback implementation for it"); mjs_ffi_sig_free(&sig); return NULL; From 7385e0ff926591b4d2846032547be6345dc6e183 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 12 Jul 2017 16:16:09 +0100 Subject: [PATCH 053/265] Support 64m and 128m flash sizes on ESP8266 PUBLISHED_FROM=1c659f426f9b4ebad564d918d303d69b1b865eb4 --- common/platforms/esp8266/rboot/rboot/rboot.c | 32 +++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/common/platforms/esp8266/rboot/rboot/rboot.c b/common/platforms/esp8266/rboot/rboot/rboot.c index 1850486..62ad3a6 100644 --- a/common/platforms/esp8266/rboot/rboot/rboot.c +++ b/common/platforms/esp8266/rboot/rboot/rboot.c @@ -201,24 +201,28 @@ uint32 NOINLINE find_image(void) { } else if (flag == 2) { ets_printf("8 Mbit\r\n"); flashsize = 0x100000; - } else if (flag == 3) { - ets_printf("16 Mbit\r\n"); -#ifdef BOOT_BIG_FLASH - flashsize = 0x200000; -#else - flashsize = 0x100000; // limit to 8Mbit -#endif - } else if (flag == 4) { - ets_printf("32 Mbit\r\n"); + } else { #ifdef BOOT_BIG_FLASH - flashsize = 0x400000; + if (flag == 3) { + ets_printf("16 Mbit\r\n"); + flashsize = 0x200000; + } else if (flag == 4) { + ets_printf("32 Mbit\r\n"); + flashsize = 0x400000; + } else if (flag == 8) { + ets_printf("64 Mbit\r\n"); + flashsize = 0x800000; + } else if (flag == 9) { + ets_printf("128 Mbit\r\n"); + flashsize = 0x1000000; + } else { + ets_printf("unknown\r\n"); + flashsize = 0x100000; // assume 8Mbit + } #else + ets_printf("8 Mbit\r\n"); flashsize = 0x100000; // limit to 8Mbit #endif - } else { - ets_printf("unknown\r\n"); - // assume at least 4mbit - flashsize = 0x80000; } // print spi mode From 484bbd67229da1b9cac0b2904cee8ba23c27917d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 12 Jul 2017 20:32:02 +0500 Subject: [PATCH 054/265] Make flasher more robust and resilient to errors Retry write if it fails mid-way, monitor rolling digest of the data being written to detect corruption early. This helps with serial adapters that lose of corrupt bytes. PUBLISHED_FROM=ec1bf5ea1be3b683d589bd433b15a6c45158df09 --- common/platforms/esp/stub_flasher.c | 124 ++++++++++++++---- common/platforms/esp/stub_flasher.h | 9 ++ common/platforms/esp32/stubs/led.c | 20 ++- .../platforms/esp8266/stubs/rom_functions.h | 3 +- common/platforms/esp8266/stubs/uart.c | 6 +- common/platforms/esp8266/stubs/uart.h | 5 + 6 files changed, 136 insertions(+), 31 deletions(-) diff --git a/common/platforms/esp/stub_flasher.c b/common/platforms/esp/stub_flasher.c index 2034066..f2bf514 100644 --- a/common/platforms/esp/stub_flasher.c +++ b/common/platforms/esp/stub_flasher.c @@ -87,10 +87,19 @@ int do_flash_erase(uint32_t addr, uint32_t len) { return 0; } +enum read_state { + READ_WAIT_START = 0, + READ_DATA = 1, + READ_UNESCAPE = 2, + READ_ERROR = 3, +}; + struct uart_buf { + enum read_state state; uint8_t data[UART_BUF_SIZE]; uint32_t nr; uint8_t *pr, *pw, *pe; + uint32_t ps; }; uint32_t ccount(void) { @@ -102,6 +111,7 @@ uint32_t ccount(void) { struct write_progress { uint32_t num_written; uint32_t buf_level; + uint8_t digest[16]; }; struct write_result { @@ -116,26 +126,71 @@ static struct uart_buf ub; void uart_isr(void *arg) { uint32_t int_st = READ_PERI_REG(UART_INT_ST_REG(0)); - uint8_t fifo_len, nr, i; - // led_on(22); + uint8_t fifo_len, nb, i; while ((fifo_len = READ_PERI_REG(UART_STATUS_REG(0))) > 0 && ub.nr < UART_BUF_SIZE) { - nr = fifo_len; - if (ub.nr + nr > UART_BUF_SIZE) nr = UART_BUF_SIZE - ub.nr; - if (nr > ub.pe - ub.pw) nr = ub.pe - ub.pw; - for (i = 0; i < nr; i++) { + nb = fifo_len; + if (ub.nr + nb > UART_BUF_SIZE) nb = UART_BUF_SIZE - ub.nr; + if (nb > ub.pe - ub.pw) nb = ub.pe - ub.pw; + for (i = 0; i < nb; i++) { uint8_t byte = READ_PERI_REG(UART_FIFO_REG(0)); - *ub.pw++ = byte; + switch (ub.state) { + case READ_WAIT_START: { + if (byte == 0xc0) { + ub.state = READ_DATA; + ub.ps = 0; + } + break; + } + case READ_DATA: { + if (byte == 0xdb) { + ub.state = READ_UNESCAPE; + } else if (byte == 0xc0) { + if (ub.ps == 0) { + /* Empty packet, sender is done. */ + ub.state = READ_ERROR; + SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0); + goto out; + } else { + ub.state = READ_WAIT_START; + } + } else { + *ub.pw++ = byte; + ub.nr++; + ub.ps++; + } + break; + } + case READ_UNESCAPE: { + if (byte == 0xdc) { + byte = 0xc0; + } else if (byte == 0xdd) { + byte = 0xdb; + } else { + ub.state = READ_ERROR; + SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0); + goto out; + } + *ub.pw++ = byte; + ub.nr++; + ub.ps++; + ub.state = READ_DATA; + break; + } + case READ_ERROR: { + goto out; + } + } } if (ub.pw == ub.pe) ub.pw = ub.data; - ub.nr += nr; } - // led_off(22); +out: WRITE_PERI_REG(UART_INT_CLR_REG(0), int_st); (void) arg; } int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { + int ret = 0; uint32_t num_erased = 0; struct MD5Context ctx; MD5Init(&ctx); @@ -144,6 +199,7 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { if (len % FLASH_SECTOR_SIZE != 0) return 0x33; if (esp_rom_spiflash_unlock() != 0) return 0x34; + ub.state = READ_WAIT_START; ub.nr = 0; ub.pr = ub.pw = ub.data; ub.pe = ub.data + UART_BUF_SIZE; @@ -169,13 +225,17 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { while (erase && num_erased < wp.num_written + FLASH_WRITE_SIZE) { const uint32_t num_left = (len - num_erased); if (num_left >= FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) { - if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) - return 0x35; + if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) { + ret = 0x35; + goto out; + } num_erased += FLASH_BLOCK_SIZE; } else { /* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */ - if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) - return 0x36; + if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) { + ret = 0x36; + goto out; + } num_erased += FLASH_SECTOR_SIZE; } } @@ -183,20 +243,21 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { start_count = ccount(); /* Wait for data to arrive. */ wp.buf_level = *nr; - // led_on(16); - while (*nr < FLASH_WRITE_SIZE) { + while (*nr < FLASH_WRITE_SIZE && ub.state != READ_ERROR) { + } + if (ub.state == READ_ERROR) { + ret = 0x37; + goto out; } - // led_off(16); wr.wait_time += ccount() - start_count; MD5Update(&ctx, ub.pr, FLASH_WRITE_SIZE); - // led_on(2); start_count = ccount(); if (esp_rom_spiflash_write(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != 0) { - return 0x37; + ret = 0x38; + goto out; } wr.write_time += ccount() - start_count; - // led_off(2); ets_intr_lock(); *nr -= FLASH_WRITE_SIZE; ets_intr_unlock(); @@ -204,17 +265,21 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { ub.pr += FLASH_WRITE_SIZE; if (ub.pr >= ub.data + UART_BUF_SIZE) ub.pr = ub.data; wp.num_written += FLASH_WRITE_SIZE; + struct MD5Context ctx2; + memcpy(&ctx2, &ctx, sizeof(ctx)); + MD5Final(wp.digest, &ctx2); SLIP_send(&wp, sizeof(wp)); } - ets_isr_mask(1 << ETS_UART0_INUM); - WRITE_PERI_REG(UART_CONF1_REG(0), saved_conf1); MD5Final(wr.digest, &ctx); wr.total_time = ccount() - wr.total_time; SLIP_send(&wr, sizeof(wr)); - return 0; +out: + WRITE_PERI_REG(UART_CONF1_REG(0), saved_conf1); + ets_isr_mask(1 << ETS_UART0_INUM); + return ret; } int do_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, @@ -286,6 +351,9 @@ int do_flash_read_chip_id(void) { uint8_t cmd_loop(void) { uint8_t cmd; do { + /* Reset FIFO to re-sync */ + SET_PERI_REG_MASK(UART_CONF0_REG(0), UART_RXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0_REG(0), UART_RXFIFO_RST); uint32_t args[4]; uint32_t len = SLIP_recv(&cmd, 1); if (len != 1) { @@ -347,6 +415,12 @@ uint8_t cmd_loop(void) { SLIP_send(&resp, 1); return cmd; } + case CMD_ECHO: { + len = SLIP_recv(args, sizeof(args)); + SLIP_send(args, len); + resp = 0; + break; + } } SLIP_send(&resp, 1); } while (cmd != CMD_BOOT_FW && cmd != CMD_REBOOT); @@ -386,7 +460,13 @@ void stub_main(void) { /* Give host time to get ready too. */ ets_delay_us(50000); +#ifdef BAUD_TEST + while (1) { + WRITE_PERI_REG(UART_FIFO_REG(0), 0x55); + } +#else SLIP_send(&greeting, 4); +#endif // led_setup(22); // led_setup(16); diff --git a/common/platforms/esp/stub_flasher.h b/common/platforms/esp/stub_flasher.h index 6c83001..ccff848 100644 --- a/common/platforms/esp/stub_flasher.h +++ b/common/platforms/esp/stub_flasher.h @@ -91,6 +91,15 @@ enum stub_cmd { * Output: None. */ CMD_REBOOT = 7, + + /* + * Echo the arguments back to the host. + * + * Args: variable. + * Input: None. + * Output: arguments. + */ + CMD_ECHO = 8, }; #endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_ */ diff --git a/common/platforms/esp32/stubs/led.c b/common/platforms/esp32/stubs/led.c index ffe566f..6cfc766 100644 --- a/common/platforms/esp32/stubs/led.c +++ b/common/platforms/esp32/stubs/led.c @@ -6,19 +6,31 @@ #include "soc/gpio_reg.h" void led_setup(int io) { - WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, 1 << io); + if (io < 32) { + WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, 1 << io); + } else { + WRITE_PERI_REG(GPIO_ENABLE1_W1TS_REG, 1 << (io - 32)); + } } void led_on(int io) { - WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io); + if (io < 32) { + WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io); + } else { + WRITE_PERI_REG(GPIO_OUT1_W1TS_REG, 1 << (io - 32)); + } } void led_off(int io) { - WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io); + if (io < 32) { + WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io); + } else { + WRITE_PERI_REG(GPIO_OUT1_W1TC_REG, 1 << (io - 32)); + } } void led_toggle(int io) { - if (READ_PERI_REG(GPIO_OUT_REG & 1 << io)) { + if (READ_PERI_REG(GPIO_OUT_REG & (1 << io))) { WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io); } else { WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io); diff --git a/common/platforms/esp8266/stubs/rom_functions.h b/common/platforms/esp8266/stubs/rom_functions.h index 8922207..b302b5f 100644 --- a/common/platforms/esp8266/stubs/rom_functions.h +++ b/common/platforms/esp8266/stubs/rom_functions.h @@ -51,8 +51,7 @@ void ets_delay_us(uint32_t delay_micros); void ets_isr_mask(uint32_t ints); void ets_isr_unmask(uint32_t ints); typedef void (*int_handler_t)(void *arg); -int_handler_t ets_isr_attach(uint32_t int_num, int_handler_t handler, - void *arg); + void ets_intr_lock(); void ets_intr_unlock(); void ets_set_user_start(void (*user_start_fn)()); diff --git a/common/platforms/esp8266/stubs/uart.c b/common/platforms/esp8266/stubs/uart.c index 5d1c643..5651bd8 100644 --- a/common/platforms/esp8266/stubs/uart.c +++ b/common/platforms/esp8266/stubs/uart.c @@ -4,11 +4,11 @@ */ #include "uart.h" +#include "ets_sys.h" #define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B -#include "rom_functions.h" - void set_baud_rate(uint32_t uart_no, uint32_t baud_rate) { - uart_div_modify(uart_no, UART_CLKDIV_26MHZ(baud_rate)); + uint32_t div = UART_CLKDIV_26MHZ(baud_rate); + WRITE_PERI_REG(UART_CLKDIV_REG(uart_no), div & 0xfffff); } diff --git a/common/platforms/esp8266/stubs/uart.h b/common/platforms/esp8266/stubs/uart.h index a2e3e4e..49b0a37 100644 --- a/common/platforms/esp8266/stubs/uart.h +++ b/common/platforms/esp8266/stubs/uart.h @@ -23,8 +23,13 @@ void set_baud_rate(uint32_t uart_no, uint32_t baud_rate); #define UART_INT_CLR_REG(i) (REG_UART_BASE(i) + 0x10) +#define UART_CLKDIV_REG(i) (REG_UART_BASE(i) + 0x14) + #define UART_STATUS_REG(i) (REG_UART_BASE(i) + 0x1C) +#define UART_CONF0_REG(i) (REG_UART_BASE(i) + 0x20) +#define UART_RXFIFO_RST (BIT(17)) + #define ETS_UART0_INUM ETS_UART_INUM #endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_ */ From 538c7c89e6fbaff5b1e04b4a25bb741a684acef0 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 18 Jul 2017 18:19:52 +0300 Subject: [PATCH 055/265] Restore SPIFFS mmap on esp32 and esp8266 PUBLISHED_FROM=de70d20697e5669b78868851a7fd7e39a0d4f5d5 --- common/platforms/esp/src/esp_mmap.c | 272 ---------------------------- common/platforms/esp/src/esp_mmap.h | 71 -------- 2 files changed, 343 deletions(-) delete mode 100644 common/platforms/esp/src/esp_mmap.c delete mode 100644 common/platforms/esp/src/esp_mmap.h diff --git a/common/platforms/esp/src/esp_mmap.c b/common/platforms/esp/src/esp_mmap.c deleted file mode 100644 index 157e4eb..0000000 --- a/common/platforms/esp/src/esp_mmap.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -/* - * This is a generic implementation of SPIFFS mmapping on esp8266 and esp32. - * - * Each of these two archs has arch-specific header which fills a few gaps, - * see e.g. fw/platforms/esp32/src/esp32_mmap.h. - * - * It already works, but there are a few major TODO-s: - * - * - Use linked list instead of fixed-size array of mmap descriptors - * - On esp32, implement reading unaligned bytes from flash in a generic - * manner, and rename read_unaligned_byte() below to read_mmapped_byte() - * - On esp32, use spi_flash_mmap() to map flash area at some address, and - * get rid of FLASH_READ_BYTE() (see fw/platforms/esp32/src/esp32_mmap.h) - */ - -#include -#include -#include - -#include "common/platforms/esp/src/esp_mmap.h" - -#include "common/cs_dbg.h" -#include "common/mbuf.h" -#include "common/spiffs/spiffs.h" -#include "common/spiffs/spiffs_nucleus.h" - -#ifdef CS_MMAP - -#define SPIFFS_PAGE_HEADER_SIZE (sizeof(spiffs_page_header)) -/* XXX: This should really be taken from a particular fs */ -#define LOG_PAGE_SIZE 256 -#define SPIFFS_PAGE_DATA_SIZE ((LOG_PAGE_SIZE) - (SPIFFS_PAGE_HEADER_SIZE)) - -#define MMAP_DESCS_ADD_SIZE 4 - -#define MMAP_ADDR_MASK ((1 << MMAP_ADDR_BITS) - 1) - -struct mbuf mmap_descs_mbuf; -struct mmap_desc *mmap_descs = NULL; -static struct mmap_desc *cur_mmap_desc; - -/* - * Reads unaligned byte, handles spiffs-mmapped addresses properly. - * - * TODO(dfrank): handle reading unaligned bytes on esp32 in a generic way, - * and rename this function to read_mmapped_byte(). - */ -IRAM NOINSTR static uint8_t read_unaligned_byte(uint8_t *addr) { - uint32_t *base = (uint32_t *) ((uintptr_t) addr & ~0x3); - uint32_t word; - - if (addr >= (uint8_t *) MMAP_BASE && addr < (uint8_t *) MMAP_END) { - struct mmap_desc *desc = MMAP_DESC_FROM_ADDR(addr); - int block = ((uintptr_t) addr & MMAP_ADDR_MASK) / SPIFFS_PAGE_DATA_SIZE; - int off = ((uintptr_t) addr & MMAP_ADDR_MASK) % SPIFFS_PAGE_DATA_SIZE; - uint8_t *ea = (uint8_t *) desc->blocks[block] + off; - - /* - * This is commented because on esp32 we might have more than one - * mount points - * - * TODO(dfrank): somehow deduce that from the address, and uncomment - */ -#if 0 - if (ea < (uint8_t *) FLASH_BASE(cs_spiffs_get_fs())) { - printf("MMAP invalid address %p: block %d, off %d, pages %d, desc %d\n", - ea, block, off, desc->pages, desc - mmap_descs); - *(int *) 1 = 1; - } -#endif - - return FLASH_READ_BYTE(ea); - } - - word = *base; - return (uint8_t)(word >> 8 * ((uintptr_t) addr & 0x3)); -} - -IRAM NOINSTR int esp_mmap_exception_handler(uint32_t vaddr, uint8_t *pc, - long *pa2) { - int pc_inc = 0; - - uint32_t instr = (uint32_t) read_unaligned_byte(pc) | ((uint32_t) read_unaligned_byte(pc + 1) << 8); - uint8_t at = (instr >> 4) & 0xf; - - uint32_t val = 0; - - if ((instr & 0xf00f) == 0x2) { - /* l8ui at, as, imm r = 0 */ - val = read_unaligned_byte((uint8_t *) vaddr); - pc_inc = 3; - } else if ((instr & 0x700f) == 0x1002) { - /* - * l16ui at, as, imm r = 1 - * l16si at, as, imm r = 9 - */ - val = read_unaligned_byte((uint8_t *) vaddr) | - read_unaligned_byte((uint8_t *) vaddr + 1) << 8; - if (instr & 0x8000) val = (int16_t) val; - pc_inc = 3; - } else if ((instr & 0xf00f) == 0x2002 || (instr & 0xf) == 0x8) { - /* - * l32i at, as, imm r = 2 - * l32i.n at, as, imm - */ - /* - * TODO(dfrank): provide fast code path for aligned access since - * all mmap 32-bit loads will be aligned. - */ - val = read_unaligned_byte((uint8_t *) vaddr) | - read_unaligned_byte((uint8_t *) vaddr + 1) << 8 | - read_unaligned_byte((uint8_t *) vaddr + 2) << 16 | - read_unaligned_byte((uint8_t *) vaddr + 3) << 24; - pc_inc = ((instr & 0xf) == 0x8) ? 2 : 3; - } else { - fprintf(stderr, "cannot emulate flash mem instr at pc = %p\n", (void *) pc); - } - - if (pc_inc > 0) { - /* - * a0 and a1 are never used as scratch registers. - * Here we assume that a2...15 are laid out contiguously in the struct. - */ - *(pa2 + at - 2) = val; - } - - return pc_inc; -} - -static struct mmap_desc *alloc_mmap_desc(void) { - size_t i; - size_t descs_cnt = mmap_descs_mbuf.len / sizeof(struct mmap_desc); - for (i = 0; i < descs_cnt; i++) { - if (mmap_descs[i].blocks == NULL) { - return &mmap_descs[i]; - } - } - - /* Failed to find an empty descriptor, need to grow mbuf */ - int old_len = mmap_descs_mbuf.len; - mbuf_append(&mmap_descs_mbuf, NULL, MMAP_DESCS_ADD_SIZE * sizeof(struct mmap_desc)); - mmap_descs = (struct mmap_desc *)mmap_descs_mbuf.buf; - memset(mmap_descs_mbuf.buf + old_len, 0, mmap_descs_mbuf.len - old_len); - - /* Call this function again; this time it should succeed */ - return alloc_mmap_desc(); -} - -void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { - int pages = (len + SPIFFS_PAGE_DATA_SIZE - 1) / SPIFFS_PAGE_DATA_SIZE; - struct mmap_desc *desc = alloc_mmap_desc(); - (void) addr; - (void) prot; - (void) flags; - (void) offset; - - if (len == 0) { - return NULL; - } - - if (desc == NULL) { - LOG(LL_ERROR, ("cannot allocate mmap desc")); - return MAP_FAILED; - } - - cur_mmap_desc = desc; - desc->pages = 0; - desc->blocks = (uint32_t *) calloc(sizeof(uint32_t), pages); - if (desc->blocks == NULL) { - LOG(LL_ERROR, ("Out of memory")); - return MAP_FAILED; - } - desc->base = MMAP_ADDR_FROM_DESC(desc); - - { - spiffs *fs; - fd = esp_translate_fd(fd, &fs); - if (fd < 0) { - LOG(LL_ERROR, ("Failed to translate fd: %d", fd)); - return NULL; - } - - int32_t t; - t = SPIFFS_read(fs, fd, DUMMY_MMAP_BUFFER_START, len); - if (t != (int32_t)len) { - LOG(LL_ERROR, ("Spiffs dummy read failed: expected len: %d, actual: %d", - len, t)); - return NULL; - } - /* - * this breaks the posix-like mmap abstraction but file descriptors are a - * scarse resource here. - */ - t = SPIFFS_close(fs, fd); - if (t != 0) { - LOG(LL_ERROR, ("Failed to close descr after dummy read: %d", t)); - return NULL; - } - } - - return desc->base; -} - -int munmap(void *addr, size_t len) { - size_t i; - size_t descs_cnt = mmap_descs_mbuf.len / sizeof(struct mmap_desc); - - (void) len; - - if (addr != NULL) { - for (i = 0; i < descs_cnt; i++) { - if (mmap_descs[i].base == addr) { - free(mmap_descs[i].blocks); - memset(&mmap_descs[i], 0, sizeof(mmap_descs[i])); - return 0; - } - } - } - - /* didn't find the mapping with the given addr */ - LOG(LL_ERROR, ("Didn't find the mapping for the addr %p", addr)); - return -1; -} - -/* - * Relocate mmapped pages. - */ -void esp_spiffs_on_page_move_hook(spiffs *fs, spiffs_file fh, - spiffs_page_ix src_pix, - spiffs_page_ix dst_pix) { - size_t i, j; - (void) fh; - uint32_t fbase = FLASH_BASE(fs); - size_t descs_cnt = mmap_descs_mbuf.len / sizeof(struct mmap_desc); - for (i = 0; i < descs_cnt; i++) { - if (mmap_descs[i].blocks) { - for (j = 0; j < mmap_descs[i].pages; j++) { - uint32_t addr = mmap_descs[i].blocks[j]; - uint32_t page = SPIFFS_PADDR_TO_PAGE(fs, addr - fbase); - if (page == src_pix) { - int delta = (int) dst_pix - (int) src_pix; - mmap_descs[i].blocks[j] += delta * LOG_PAGE_SIZE; - } - } - } - } -} - -int esp_spiffs_dummy_read(spiffs *fs, u32_t addr, u32_t size, u8_t *dst) { - (void) size; - - if (dst >= DUMMY_MMAP_BUFFER_START && dst < DUMMY_MMAP_BUFFER_END) { - if ((addr - SPIFFS_PAGE_HEADER_SIZE) % SPIFFS_CFG_LOG_PAGE_SZ(fs) == 0) { - addr &= MMAP_ADDR_MASK; - cur_mmap_desc->blocks[cur_mmap_desc->pages++] = FLASH_BASE(fs) + addr; - } - return 1; - } - - return 0; -} - -void esp_mmap_init(void) { - mbuf_init(&mmap_descs_mbuf, 0); -} - -#endif /* CS_MMAP */ diff --git a/common/platforms/esp/src/esp_mmap.h b/common/platforms/esp/src/esp_mmap.h deleted file mode 100644 index 9965228..0000000 --- a/common/platforms/esp/src/esp_mmap.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_ESP_SRC_ESP_MMAP_H_ -#define CS_COMMON_PLATFORMS_ESP_SRC_ESP_MMAP_H_ - -#include - -#include "common/spiffs/spiffs.h" -#include "common/platform.h" - -/* - * Platform-dependent header should define the following macros: - * - * - MMAP_BASE: base address for mmapped points; e.g. ((void *) 0x10000000) - * - MMAP_END: end address for mmapped points; e.g. ((void *) 0x20000000) - * - * So with the example values given above, the range 0x10000000 - 0x20000000 is - * used for all mmapped areas. We need to partition it further, by choosing the - * optimal tradeoff between the max number of mmapped areas and the max size - * of the mmapped area. Within the example range, we have 28 bits, and we - * need to define two more macros which will define how these bits are used: - * - * - MMAP_ADDR_BITS: how many bits are used for the address within each - * mmapped area; - * - MMAP_NUM_BITS: how many bits are used for the number of mmapped area. - */ - -#if CS_PLATFORM == CS_P_ESP32 -#include "fw/platforms/esp32/src/esp32_fs.h" -#include "fw/platforms/esp32/src/esp32_mmap.h" -#elif CS_PLATFORM == CS_P_ESP8266 -#include "fw/platforms/esp8266/src/esp8266_mmap.h" -#include "fw/platforms/esp8266/src/esp_fs.h" -#else -#error unsupported CS_PLATFORM: only esp32 and esp8266 are supported -#endif - -#ifdef CS_MMAP - -#define MMAP_NUM_MASK ((1 << MMAP_NUM_BITS) - 1) - -#define MMAP_DESC_FROM_ADDR(addr) \ - (&mmap_descs[(((uintptr_t) addr) >> MMAP_ADDR_BITS) & MMAP_NUM_MASK]) -#define MMAP_ADDR_FROM_DESC(desc) \ - ((void *) ((uintptr_t) MMAP_BASE | ((desc - mmap_descs) << MMAP_ADDR_BITS))) - -struct mmap_desc { - void *base; - uint32_t pages; - uint32_t *blocks; /* pages long */ -}; - -extern struct mmap_desc *mmap_descs; - -IRAM NOINSTR int esp_mmap_exception_handler(uint32_t vaddr, uint8_t *pc, - long *pa2); -int esp_spiffs_dummy_read(spiffs *fs, u32_t addr, u32_t size, u8_t *dst); - -/* - * Arch-dependent: translates vfs file descriptor from vfs to a spiffs file - * descriptor; also returns an instance of spiffs through the pointer. - */ -int esp_translate_fd(int fd, spiffs **pfs); - -void esp_mmap_init(void); - -#endif /* CS_MMAP */ -#endif /* CS_COMMON_PLATFORMS_ESP_SRC_ESP_MMAP_H_ */ From 95e90cfc340e1e4ff2aed70d2ecfb9997d809fa9 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 18 Jul 2017 16:22:52 +0100 Subject: [PATCH 056/265] Remove debug leftover PUBLISHED_FROM=bb57a780327350a09b6e6a8d6833c148a1cbfe76 --- mjs.c | 4 ---- mjs/src/mjs_exec.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/mjs.c b/mjs.c index e489c87..568cd40 100644 --- a/mjs.c +++ b/mjs.c @@ -7842,10 +7842,6 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { struct mjs_bcode_part bp = *mjs_bcode_part_get_by_offset(mjs, off); off -= bp.start_idx; - static int aaa = 0; - if (aaa++ >= 1) { - // abort(); - } for (i = off; i < bp.data.len; i++) { mjs->cur_bcode_offset = i; diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index be7b626..df79e34 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -498,10 +498,6 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { struct mjs_bcode_part bp = *mjs_bcode_part_get_by_offset(mjs, off); off -= bp.start_idx; - static int aaa = 0; - if (aaa++ >= 1) { - // abort(); - } for (i = off; i < bp.data.len; i++) { mjs->cur_bcode_offset = i; From 8c497d7fc09191c649750818a7cc0a91dda3e8bd Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 19 Jul 2017 14:20:58 +0200 Subject: [PATCH 057/265] Add support for 3-arg functions with doubles Also refactor existing implementation to be shorter PUBLISHED_FROM=f47c567b47f5f0153b3ea84ea0176a549d56cff0 --- mjs.c | 221 +++++++++++++++++++++++++++++++++--------- mjs/src/ffi/ffi.c | 221 +++++++++++++++++++++++++++++++++--------- mjs/tests/unit_test.c | 12 +++ 3 files changed, 358 insertions(+), 96 deletions(-) diff --git a/mjs.c b/mjs.c index 568cd40..5f280a6 100644 --- a/mjs.c +++ b/mjs.c @@ -6035,6 +6035,12 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { /* Amalgamated: #include "mjs/src/ffi/ffi.h" */ +#define IS_W(arg) ((arg).ctype == FFI_CTYPE_WORD) +#define IS_D(arg) ((arg).ctype == FFI_CTYPE_DOUBLE) + +#define W(arg) ((ffi_word_t)(arg).v.i) +#define D(arg) ((arg).v.d) + void ffi_set_word(struct ffi_arg *arg, ffi_word_t v) { arg->ctype = FFI_CTYPE_WORD; arg->v.i = v; @@ -6094,10 +6100,19 @@ typedef ffi_word_t (*w5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef ffi_word_t (*w6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); + typedef ffi_word_t (*wdw_t)(double, ffi_word_t); typedef ffi_word_t (*wwd_t)(ffi_word_t, double); typedef ffi_word_t (*wdd_t)(double, double); +typedef ffi_word_t (*wwwd_t)(ffi_word_t, ffi_word_t, double); +typedef ffi_word_t (*wwdw_t)(ffi_word_t, double, ffi_word_t); +typedef ffi_word_t (*wwdd_t)(ffi_word_t, double, double); +typedef ffi_word_t (*wdww_t)(double, ffi_word_t, ffi_word_t); +typedef ffi_word_t (*wdwd_t)(double, ffi_word_t, double); +typedef ffi_word_t (*wddw_t)(double, double, ffi_word_t); +typedef ffi_word_t (*wddd_t)(double, double, double); + typedef bool (*b4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef bool (*b5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -6107,6 +6122,14 @@ typedef bool (*bdw_t)(double, ffi_word_t); typedef bool (*bwd_t)(ffi_word_t, double); typedef bool (*bdd_t)(double, double); +typedef bool (*bwwd_t)(ffi_word_t, ffi_word_t, double); +typedef bool (*bwdw_t)(ffi_word_t, double, ffi_word_t); +typedef bool (*bwdd_t)(ffi_word_t, double, double); +typedef bool (*bdww_t)(double, ffi_word_t, ffi_word_t); +typedef bool (*bdwd_t)(double, ffi_word_t, double); +typedef bool (*bddw_t)(double, double, ffi_word_t); +typedef bool (*bddd_t)(double, double, double); + typedef double (*d4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef double (*d5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -6116,15 +6139,22 @@ typedef double (*ddw_t)(double, ffi_word_t); typedef double (*dwd_t)(ffi_word_t, double); typedef double (*ddd_t)(double, double); +typedef double (*dwwd_t)(ffi_word_t, ffi_word_t, double); +typedef double (*dwdw_t)(ffi_word_t, double, ffi_word_t); +typedef double (*dwdd_t)(ffi_word_t, double, double); +typedef double (*ddww_t)(double, ffi_word_t, ffi_word_t); +typedef double (*ddwd_t)(double, ffi_word_t, double); +typedef double (*dddw_t)(double, double, ffi_word_t); +typedef double (*dddd_t)(double, double, double); + int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, struct ffi_arg *args) { int i, doubles = 0; if (nargs > 6) return -1; for (i = 0; i < nargs; i++) { - doubles += (args[i].ctype == FFI_CTYPE_DOUBLE); + doubles += (IS_D(args[i])); } - if (doubles > 0 && nargs > 2) return -1; switch (res->ctype) { case FFI_CTYPE_WORD: { @@ -6135,35 +6165,67 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { w4w_t f = (w4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { w5w_t f = (w5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { w6w_t f = (w6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - wdw_t f = (wdw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - wwd_t f = (wwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + wdw_t f = (wdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + wwd_t f = (wwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wwwd_t f = (wwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wwdw_t f = (wwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wwdd_t f = (wwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wdww_t f = (wdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wdwd_t f = (wdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wddw_t f = (wddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wddd_t f = (wddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } break; case 2: { wdd_t f = (wdd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; @@ -6178,36 +6240,67 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { b4w_t f = (b4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { b5w_t f = (b5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { b6w_t f = (b6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: { - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - bdw_t f = (bdw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - bwd_t f = (bwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + bdw_t f = (bdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + bwd_t f = (bwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bwwd_t f = (bwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bwdw_t f = (bwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bwdd_t f = (bwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bdww_t f = (bdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bdwd_t f = (bdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bddw_t f = (bddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bddd_t f = (bddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } - break; } case 2: { bdd_t f = (bdd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; @@ -6222,36 +6315,68 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { d4w_t f = (d4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { d5w_t f = (d5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { d6w_t f = (d6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: { - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - ddw_t f = (ddw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - dwd_t f = (dwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + ddw_t f = (ddw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + dwd_t f = (dwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + dwwd_t f = (dwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dwdw_t f = (dwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dwdd_t f = (dwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ddww_t f = (ddww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + ddwd_t f = (ddwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dddw_t f = (dddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dddd_t f = (dddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } break; } case 2: { ddd_t f = (ddd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; diff --git a/mjs/src/ffi/ffi.c b/mjs/src/ffi/ffi.c index 1ab9188..37d4cc8 100644 --- a/mjs/src/ffi/ffi.c +++ b/mjs/src/ffi/ffi.c @@ -5,6 +5,12 @@ #include "mjs/src/ffi/ffi.h" +#define IS_W(arg) ((arg).ctype == FFI_CTYPE_WORD) +#define IS_D(arg) ((arg).ctype == FFI_CTYPE_DOUBLE) + +#define W(arg) ((ffi_word_t)(arg).v.i) +#define D(arg) ((arg).v.d) + void ffi_set_word(struct ffi_arg *arg, ffi_word_t v) { arg->ctype = FFI_CTYPE_WORD; arg->v.i = v; @@ -64,10 +70,19 @@ typedef ffi_word_t (*w5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef ffi_word_t (*w6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); + typedef ffi_word_t (*wdw_t)(double, ffi_word_t); typedef ffi_word_t (*wwd_t)(ffi_word_t, double); typedef ffi_word_t (*wdd_t)(double, double); +typedef ffi_word_t (*wwwd_t)(ffi_word_t, ffi_word_t, double); +typedef ffi_word_t (*wwdw_t)(ffi_word_t, double, ffi_word_t); +typedef ffi_word_t (*wwdd_t)(ffi_word_t, double, double); +typedef ffi_word_t (*wdww_t)(double, ffi_word_t, ffi_word_t); +typedef ffi_word_t (*wdwd_t)(double, ffi_word_t, double); +typedef ffi_word_t (*wddw_t)(double, double, ffi_word_t); +typedef ffi_word_t (*wddd_t)(double, double, double); + typedef bool (*b4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef bool (*b5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -77,6 +92,14 @@ typedef bool (*bdw_t)(double, ffi_word_t); typedef bool (*bwd_t)(ffi_word_t, double); typedef bool (*bdd_t)(double, double); +typedef bool (*bwwd_t)(ffi_word_t, ffi_word_t, double); +typedef bool (*bwdw_t)(ffi_word_t, double, ffi_word_t); +typedef bool (*bwdd_t)(ffi_word_t, double, double); +typedef bool (*bdww_t)(double, ffi_word_t, ffi_word_t); +typedef bool (*bdwd_t)(double, ffi_word_t, double); +typedef bool (*bddw_t)(double, double, ffi_word_t); +typedef bool (*bddd_t)(double, double, double); + typedef double (*d4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef double (*d5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -86,15 +109,22 @@ typedef double (*ddw_t)(double, ffi_word_t); typedef double (*dwd_t)(ffi_word_t, double); typedef double (*ddd_t)(double, double); +typedef double (*dwwd_t)(ffi_word_t, ffi_word_t, double); +typedef double (*dwdw_t)(ffi_word_t, double, ffi_word_t); +typedef double (*dwdd_t)(ffi_word_t, double, double); +typedef double (*ddww_t)(double, ffi_word_t, ffi_word_t); +typedef double (*ddwd_t)(double, ffi_word_t, double); +typedef double (*dddw_t)(double, double, ffi_word_t); +typedef double (*dddd_t)(double, double, double); + int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, struct ffi_arg *args) { int i, doubles = 0; if (nargs > 6) return -1; for (i = 0; i < nargs; i++) { - doubles += (args[i].ctype == FFI_CTYPE_DOUBLE); + doubles += (IS_D(args[i])); } - if (doubles > 0 && nargs > 2) return -1; switch (res->ctype) { case FFI_CTYPE_WORD: { @@ -105,35 +135,67 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { w4w_t f = (w4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { w5w_t f = (w5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { w6w_t f = (w6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - wdw_t f = (wdw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - wwd_t f = (wwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + wdw_t f = (wdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + wwd_t f = (wwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wwwd_t f = (wwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wwdw_t f = (wwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wwdd_t f = (wwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wdww_t f = (wdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wdwd_t f = (wdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wddw_t f = (wddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wddd_t f = (wddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } break; case 2: { wdd_t f = (wdd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; @@ -148,36 +210,67 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { b4w_t f = (b4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { b5w_t f = (b5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { b6w_t f = (b6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: { - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - bdw_t f = (bdw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - bwd_t f = (bwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + bdw_t f = (bdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + bwd_t f = (bwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bwwd_t f = (bwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bwdw_t f = (bwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bwdd_t f = (bwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bdww_t f = (bdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bdwd_t f = (bdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bddw_t f = (bddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bddd_t f = (bddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } - break; } case 2: { bdd_t f = (bdd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; @@ -192,36 +285,68 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, */ if (nargs <= 4) { d4w_t f = (d4w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); } else if (nargs == 5) { d5w_t f = (d5w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); } else if (nargs == 6) { d6w_t f = (d6w_t) func; - r = f((ffi_word_t) args[0].v.i, (ffi_word_t) args[1].v.i, - (ffi_word_t) args[2].v.i, (ffi_word_t) args[3].v.i, - (ffi_word_t) args[4].v.i, (ffi_word_t) args[5].v.i); + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); } else { abort(); } break; } case 1: { - if (args[0].ctype == FFI_CTYPE_DOUBLE) { - ddw_t f = (ddw_t) func; - r = f(args[0].v.d, (ffi_word_t) args[1].v.i); - } else { - dwd_t f = (dwd_t) func; - r = f((ffi_word_t) args[0].v.i, args[1].v.d); + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0])) { + ddw_t f = (ddw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + dwd_t f = (dwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + dwwd_t f = (dwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dwdw_t f = (dwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dwdd_t f = (dwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ddww_t f = (ddww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + ddwd_t f = (ddwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dddw_t f = (dddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dddd_t f = (dddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } break; } case 2: { ddd_t f = (ddd_t) func; - r = f(args[0].v.d, args[1].v.d); + r = f(D(args[0]), D(args[1])); } break; default: return -1; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 06b4406..75dd2a6 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -636,6 +636,10 @@ int ffi_test_i2i(int a0, int a1) { return a0 - a1; } +int ffi_test_iiid(int a0, int a1, double d2) { + return (d2 * a0 - a1) * 1000; +} + int ffi_test_iib(int a0, bool b) { return a0 - (b ? 10 : 20); } @@ -753,6 +757,7 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "ffi_get_null") == 0) return ffi_get_null; if (strcmp(name, "ffi_set_byte") == 0) return ffi_set_byte; if (strcmp(name, "ffi_test_i2i") == 0) return ffi_test_i2i; + if (strcmp(name, "ffi_test_iiid") == 0) return ffi_test_iiid; if (strcmp(name, "ffi_test_iib") == 0) return ffi_test_iib; if (strcmp(name, "ffi_test_bi") == 0) return ffi_test_bi; if (strcmp(name, "ffi_test_i5i") == 0) return ffi_test_i5i; @@ -1056,6 +1061,13 @@ const char *test_call_ffi(struct mjs *mjs) { /* ASSERT_STREQ(p, "ab"); */ } + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_iiid = ffi('int ffi_test_iiid(int, int, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_iiid(3, 2, 13.3)", &res), MJS_OK); + ASSERT_EQ(mjs_get_int(mjs, res), 37900); + mjs_disown(mjs, &res); return NULL; From ec6e3614d5163e6954fb199f92058fcfa9e431b2 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 19 Jul 2017 16:24:10 +0200 Subject: [PATCH 058/265] Fix ffi calls returning boolean And add more tests PUBLISHED_FROM=cd07cd52c8e178cb5a15cc5a4f2eef04ab9c42ab --- mjs.c | 1 + mjs/src/ffi/ffi.c | 1 + mjs/tests/unit_test.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index 5f280a6..5e1d29c 100644 --- a/mjs.c +++ b/mjs.c @@ -6297,6 +6297,7 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } + break; } case 2: { bdd_t f = (bdd_t) func; diff --git a/mjs/src/ffi/ffi.c b/mjs/src/ffi/ffi.c index 37d4cc8..c9ebabc 100644 --- a/mjs/src/ffi/ffi.c +++ b/mjs/src/ffi/ffi.c @@ -267,6 +267,7 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } + break; } case 2: { bdd_t f = (bdd_t) func; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 75dd2a6..3c1ef50 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -640,6 +640,16 @@ int ffi_test_iiid(int a0, int a1, double d2) { return (d2 * a0 - a1) * 1000; } +bool ffi_test_biid(int a0, int a1, double d2) { + (void) a0; + (void) a1; + return d2 > 10.0; +} + +double ffi_test_diid(int a0, int a1, double d2) { + return d2 * a0 - a1; +} + int ffi_test_iib(int a0, bool b) { return a0 - (b ? 10 : 20); } @@ -758,6 +768,8 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "ffi_set_byte") == 0) return ffi_set_byte; if (strcmp(name, "ffi_test_i2i") == 0) return ffi_test_i2i; if (strcmp(name, "ffi_test_iiid") == 0) return ffi_test_iiid; + if (strcmp(name, "ffi_test_biid") == 0) return ffi_test_biid; + if (strcmp(name, "ffi_test_diid") == 0) return ffi_test_diid; if (strcmp(name, "ffi_test_iib") == 0) return ffi_test_iib; if (strcmp(name, "ffi_test_bi") == 0) return ffi_test_bi; if (strcmp(name, "ffi_test_i5i") == 0) return ffi_test_i5i; @@ -1065,8 +1077,25 @@ const char *test_call_ffi(struct mjs *mjs) { mjs_exec(mjs, "let ffi_test_iiid = ffi('int ffi_test_iiid(int, int, double)')", &res)); - ASSERT_EQ(mjs_exec(mjs, "ffi_test_iiid(3, 2, 13.3)", &res), MJS_OK); - ASSERT_EQ(mjs_get_int(mjs, res), 37900); + ASSERT_EQ(mjs_exec(mjs, "ffi_test_iiid(3, 2, 13.4)", &res), MJS_OK); + ASSERT_EQ(mjs_get_int(mjs, res), 38200); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_diid = ffi('double ffi_test_diid(int, int, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_diid(3, 2, 13.4)", &res), MJS_OK); + ASSERT_EQ(mjs_get_double(mjs, res), 38.2); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_biid = ffi('bool ffi_test_biid(int, int, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biid(0, 0, 10)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biid(0, 0, 10.1)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); mjs_disown(mjs, &res); From 5c059e0fbc6db333a8cd140aab8855d809e1c153 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 20 Jul 2017 11:20:59 +0300 Subject: [PATCH 059/265] Fix https://github.com/cesanta/mjs/issues/36 PUBLISHED_FROM=7879242ec3e42206e3827dcef0cf38a68065e846 --- mjs.c | 12 ++++++++++-- mjs/src/mjs_parser.c | 12 ++++++++++-- mjs/tests/unit_test.c | 10 ++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index 5e1d29c..675baeb 100644 --- a/mjs.c +++ b/mjs.c @@ -11850,8 +11850,16 @@ static mjs_err_t parse_statement(struct pstate *p) { mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "[%.*s] is not implemented", p->tok.len, p->tok.ptr); return MJS_SYNTAX_ERROR; - default: - return parse_expr(p); + default: { + mjs_err_t res = MJS_OK; + for (;;) { + if ((res = parse_expr(p)) != MJS_OK) return res; + if (p->tok.tok != TOK_COMMA) break; + emit_byte(p, OP_DROP); + pnext1(p); + } + return res; + } } } diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index 9e66ffa..ac7c674 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -881,8 +881,16 @@ static mjs_err_t parse_statement(struct pstate *p) { mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "[%.*s] is not implemented", p->tok.len, p->tok.ptr); return MJS_SYNTAX_ERROR; - default: - return parse_expr(p); + default: { + mjs_err_t res = MJS_OK; + for (;;) { + if ((res = parse_expr(p)) != MJS_OK) return res; + if (p->tok.tok != TOK_COMMA) break; + emit_byte(p, OP_DROP); + pnext1(p); + } + return res; + } } } diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 3c1ef50..ba2b136 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -3330,9 +3330,19 @@ const char *test_lib_math(struct mjs *mjs) { return NULL; } +const char *test_parser(struct mjs *mjs) { + mjs_val_t res = MJS_UNDEFINED; + mjs_own(mjs, &res); + CHECK_NUMERIC("1,2,3", 3); + CHECK_NUMERIC("let f = function(x){return x;}; f(1),f(2),f(3)", 3); + mjs_disown(mjs, &res); + return NULL; +} + static const char *run_all_tests(const char *filter, double *total_elapsed) { cs_log_set_level(2); + RUN_TEST_MJS(test_parser); RUN_TEST_MJS(test_arithmetic); RUN_TEST_MJS(test_block); RUN_TEST_MJS(test_function); From 915bf7f8dcd2dcea28fd7d1ecc63e970293844e7 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 20 Jul 2017 11:41:59 +0300 Subject: [PATCH 060/265] Fix https://github.com/cesanta/mjs/issues/39 PUBLISHED_FROM=4d33ffcfec33bd347ae2b0137f50d97930c4e653 --- mjs.c | 4 ++++ mjs/src/mjs_parser.c | 4 ++++ mjs/tests/unit_test.c | 2 ++ 3 files changed, 10 insertions(+) diff --git a/mjs.c b/mjs.c index 675baeb..88ca5f1 100644 --- a/mjs.c +++ b/mjs.c @@ -11814,6 +11814,10 @@ static mjs_err_t parse_return(struct pstate *p) { static mjs_err_t parse_statement(struct pstate *p) { LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr)); switch (p->tok.tok) { + case TOK_SEMICOLON: + emit_byte(p, OP_PUSH_UNDEF); + pnext1(p); + return MJS_OK; case TOK_KEYWORD_LET: return parse_let(p); case TOK_OPEN_CURLY: diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index ac7c674..3d33415 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -845,6 +845,10 @@ static mjs_err_t parse_return(struct pstate *p) { static mjs_err_t parse_statement(struct pstate *p) { LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr)); switch (p->tok.tok) { + case TOK_SEMICOLON: + emit_byte(p, OP_PUSH_UNDEF); + pnext1(p); + return MJS_OK; case TOK_KEYWORD_LET: return parse_let(p); case TOK_OPEN_CURLY: diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index ba2b136..113fe4f 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -3335,6 +3335,8 @@ const char *test_parser(struct mjs *mjs) { mjs_own(mjs, &res); CHECK_NUMERIC("1,2,3", 3); CHECK_NUMERIC("let f = function(x){return x;}; f(1),f(2),f(3)", 3); + ASSERT_EXEC_OK(mjs_exec(mjs, ";", &res)); + ASSERT_EQ(res, MJS_UNDEFINED); mjs_disown(mjs, &res); return NULL; } From 4cee9a9a13e77201d8b37791d9eef34c70694c9a Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 20 Jul 2017 15:25:50 +0300 Subject: [PATCH 061/265] Fix inequality test And make sure the same code is used for both equality and inequality tests PUBLISHED_FROM=c1007e8d4178ecbdc99dac894bb8fe87828997e9 --- mjs.c | 46 ++++++++++++++++++++++--------------------- mjs/src/mjs_exec.c | 46 ++++++++++++++++++++++--------------------- mjs/tests/unit_test.c | 18 +++++++++++++++++ 3 files changed, 66 insertions(+), 44 deletions(-) diff --git a/mjs.c b/mjs.c index 88ca5f1..3fbd086 100644 --- a/mjs.c +++ b/mjs.c @@ -7641,6 +7641,28 @@ static void op_assign(struct mjs *mjs, int op) { } } +static int check_equal(struct mjs *mjs, mjs_val_t a, mjs_val_t b) { + int ret = 0; + if (a == b) { + ret = 1; + } else if (mjs_is_number(a) && mjs_is_number(b)) { + /* + * The case of equal numbers is handled above, so here the result is always + * false + */ + ret = 0; + } else if (mjs_is_string(a) && mjs_is_string(b)) { + ret = s_cmp(mjs, a, b) == 0; + } else if (mjs_is_foreign(a) && b == MJS_NULL) { + ret = mjs_get_ptr(mjs, a) == NULL; + } else if (a == MJS_NULL && mjs_is_foreign(b)) { + ret = mjs_get_ptr(mjs, b) == NULL; + } else { + ret = 0; + } + return ret; +} + static void exec_expr(struct mjs *mjs, int op) { switch (op) { case TOK_DOT: @@ -7687,33 +7709,13 @@ static void exec_expr(struct mjs *mjs, int op) { case TOK_EQ_EQ: { mjs_val_t a = mjs_pop(mjs); mjs_val_t b = mjs_pop(mjs); - if (a == b) { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } else if (mjs_is_number(a) && mjs_is_number(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } else if (mjs_is_string(a) && mjs_is_string(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, s_cmp(mjs, a, b) == 0)); - } else if (mjs_is_foreign(a) && b == MJS_NULL) { - mjs_push(mjs, mjs_mk_boolean(mjs, mjs_get_ptr(mjs, a) == NULL)); - } else if (a == MJS_NULL && mjs_is_foreign(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, mjs_get_ptr(mjs, b) == NULL)); - } else { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } + mjs_push(mjs, mjs_mk_boolean(mjs, check_equal(mjs, a, b))); break; } case TOK_NE_NE: { mjs_val_t a = mjs_pop(mjs); mjs_val_t b = mjs_pop(mjs); - if (a == b) { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } else if (mjs_is_number(a) && mjs_is_number(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } else if (mjs_is_string(a) && mjs_is_string(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, s_cmp(mjs, a, b) != 0)); - } else { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } + mjs_push(mjs, mjs_mk_boolean(mjs, !check_equal(mjs, a, b))); break; } case TOK_LT: { diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index df79e34..3a2d190 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -171,6 +171,28 @@ static void op_assign(struct mjs *mjs, int op) { } } +static int check_equal(struct mjs *mjs, mjs_val_t a, mjs_val_t b) { + int ret = 0; + if (a == b) { + ret = 1; + } else if (mjs_is_number(a) && mjs_is_number(b)) { + /* + * The case of equal numbers is handled above, so here the result is always + * false + */ + ret = 0; + } else if (mjs_is_string(a) && mjs_is_string(b)) { + ret = s_cmp(mjs, a, b) == 0; + } else if (mjs_is_foreign(a) && b == MJS_NULL) { + ret = mjs_get_ptr(mjs, a) == NULL; + } else if (a == MJS_NULL && mjs_is_foreign(b)) { + ret = mjs_get_ptr(mjs, b) == NULL; + } else { + ret = 0; + } + return ret; +} + static void exec_expr(struct mjs *mjs, int op) { switch (op) { case TOK_DOT: @@ -217,33 +239,13 @@ static void exec_expr(struct mjs *mjs, int op) { case TOK_EQ_EQ: { mjs_val_t a = mjs_pop(mjs); mjs_val_t b = mjs_pop(mjs); - if (a == b) { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } else if (mjs_is_number(a) && mjs_is_number(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } else if (mjs_is_string(a) && mjs_is_string(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, s_cmp(mjs, a, b) == 0)); - } else if (mjs_is_foreign(a) && b == MJS_NULL) { - mjs_push(mjs, mjs_mk_boolean(mjs, mjs_get_ptr(mjs, a) == NULL)); - } else if (a == MJS_NULL && mjs_is_foreign(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, mjs_get_ptr(mjs, b) == NULL)); - } else { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } + mjs_push(mjs, mjs_mk_boolean(mjs, check_equal(mjs, a, b))); break; } case TOK_NE_NE: { mjs_val_t a = mjs_pop(mjs); mjs_val_t b = mjs_pop(mjs); - if (a == b) { - mjs_push(mjs, mjs_mk_boolean(mjs, 0)); - } else if (mjs_is_number(a) && mjs_is_number(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } else if (mjs_is_string(a) && mjs_is_string(b)) { - mjs_push(mjs, mjs_mk_boolean(mjs, s_cmp(mjs, a, b) != 0)); - } else { - mjs_push(mjs, mjs_mk_boolean(mjs, 1)); - } + mjs_push(mjs, mjs_mk_boolean(mjs, !check_equal(mjs, a, b))); break; } case TOK_LT: { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 113fe4f..dca229e 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2808,6 +2808,24 @@ const char *test_foreign_ptr(struct mjs *mjs) { ), &res)); ASSERT_EQ(mjs_get_bool(mjs, res), 0); + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + let get_null = ffi('void *ffi_get_null()'); + let ptr = get_null(); + ptr !== null + ), &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + let calloc = ffi('void *calloc(int, int)'); + let free = ffi('void free(void *)'); + let ptr = calloc(100, 1); + free(ptr); + ptr !== null + ), &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + ASSERT_EXEC_OK(mjs_exec(mjs, STRINGIFY( let set_byte = ffi('void ffi_set_byte(void *, int)'); From 2d8c3bb827a121d8f6afebaa40025579ea594fc4 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 24 Jul 2017 17:14:17 +0300 Subject: [PATCH 062/265] Flasher stub optimizations - Compression support - Async erase This yields dramatic improvement at lower flashing speeds: at 460800 (the default baud rate), full ESP32 flashing of mos_apps/default is 25 seconds, down from 40; ESP8266 is 15 (down from 25). At 1500000 the speedup is less impressive, approx 10-15%. Removed the erase function of the stub to cut down on size a bit. PUBLISHED_FROM=70f4628f680c576c9d7087edeab3185ba0c3a633 --- common/platforms/esp/stub_flasher.c | 232 +++++++++++------- common/platforms/esp/stub_flasher.h | 9 - common/platforms/esp8266/rom/ESP8266_ROM.txt | 173 +++++++------ common/platforms/esp8266/rom/rom.S | 8 + common/platforms/esp8266/rom/rom.elf | Bin 79692 -> 79956 bytes common/platforms/esp8266/stubs/Makefile | 3 +- .../platforms/esp8266/stubs/rom_functions.h | 12 +- common/platforms/esp8266/stubs/stub.ld | 4 +- 8 files changed, 266 insertions(+), 175 deletions(-) diff --git a/common/platforms/esp/stub_flasher.c b/common/platforms/esp/stub_flasher.c index f2bf514..17d08b4 100644 --- a/common/platforms/esp/stub_flasher.c +++ b/common/platforms/esp/stub_flasher.c @@ -27,7 +27,10 @@ #if defined(ESP8266) #include "eagle_soc.h" #include "ets_sys.h" +#include "../../../miniz.c" #elif defined(ESP32) +#include "rom/miniz.h" +#include "rom/spi_flash.h" #include "soc/uart_reg.h" #include "led.h" #endif @@ -43,8 +46,9 @@ uint32_t params[1] __attribute__((section(".params"))); #define FLASH_PAGE_SIZE 256 /* These consts should be in sync with flasher_client.go */ -#define UART_BUF_SIZE (8 * FLASH_SECTOR_SIZE) -#define FLASH_WRITE_SIZE FLASH_SECTOR_SIZE +#define NUM_BUFS 4 +#define BUF_SIZE 4096 +#define FLASH_WRITE_SIZE BUF_SIZE #define UART_RX_INTS (UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA) @@ -54,55 +58,42 @@ extern uint32_t _bss_start, _bss_end; #define REG_SPI_BASE(i) (0x60000200 - i * 0x100) #define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0) +#define SPI_FLASH_WREN (BIT(30)) #define SPI_FLASH_RDID (BIT(28)) +#define SPI_FLASH_SE (BIT(24)) +#define SPI_FLASH_BE (BIT(23)) -#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x40) -#endif - -int do_flash_erase(uint32_t addr, uint32_t len) { - if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; - if (len % FLASH_SECTOR_SIZE != 0) return 0x33; - if (esp_rom_spiflash_unlock() != 0) return 0x34; +#define SPI_ADDR_REG(i) (REG_SPI_BASE(i) + 0x4) - while (len > 0 && (addr % FLASH_BLOCK_SIZE != 0)) { - if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) - return 0x35; - len -= FLASH_SECTOR_SIZE; - addr += FLASH_SECTOR_SIZE; - } +#define SPI_USER_REG(i) (REG_SPI_BASE(i) + 0x1C) - while (len > FLASH_BLOCK_SIZE) { - if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; - len -= FLASH_BLOCK_SIZE; - addr += FLASH_BLOCK_SIZE; - } - - while (len > 0) { - if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) - return 0x37; - len -= FLASH_SECTOR_SIZE; - addr += FLASH_SECTOR_SIZE; - } - - return 0; -} +#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x40) +#endif enum read_state { READ_WAIT_START = 0, - READ_DATA = 1, - READ_UNESCAPE = 2, - READ_ERROR = 3, + READ_FLAGS, + READ_DATA, + READ_UNESCAPE, + READ_ERROR, +}; + +struct data_buf { + uint32_t len; + uint8_t data[BUF_SIZE]; + uint8_t flags; }; +#define FLAG_COMPRESSED 1 + struct uart_buf { enum read_state state; - uint8_t data[UART_BUF_SIZE]; - uint32_t nr; - uint8_t *pr, *pw, *pe; + struct data_buf bufs[NUM_BUFS]; + uint32_t bri, bwi; uint32_t ps; }; -uint32_t ccount(void) { +static inline uint32_t ccount(void) { uint32_t r; __asm volatile("rsr.ccount %0" : "=a"(r)); return r; @@ -116,6 +107,7 @@ struct write_progress { struct write_result { uint32_t wait_time; + uint32_t decomp_time; uint32_t write_time; uint32_t erase_time; uint32_t total_time; @@ -123,31 +115,46 @@ struct write_result { }; static struct uart_buf ub; +static uint32_t inflate_buf[TINFL_LZ_DICT_SIZE / sizeof(uint32_t)]; + +static void next_write_buf(void) { + ub.bwi++; + if (ub.bwi == NUM_BUFS) ub.bwi = 0; + ub.bufs[ub.bwi].len = 0; + ub.bufs[ub.bwi].flags = 0; +} + +static void add_byte(uint8_t byte) { + struct data_buf *buf = &ub.bufs[ub.bwi]; + if (buf->len < BUF_SIZE) { + buf->data[buf->len++] = byte; + ub.ps++; + } +} void uart_isr(void *arg) { uint32_t int_st = READ_PERI_REG(UART_INT_ST_REG(0)); - uint8_t fifo_len, nb, i; - while ((fifo_len = READ_PERI_REG(UART_STATUS_REG(0))) > 0 && - ub.nr < UART_BUF_SIZE) { - nb = fifo_len; - if (ub.nr + nb > UART_BUF_SIZE) nb = UART_BUF_SIZE - ub.nr; - if (nb > ub.pe - ub.pw) nb = ub.pe - ub.pw; - for (i = 0; i < nb; i++) { + uint8_t fifo_len, i; + while ((fifo_len = READ_PERI_REG(UART_STATUS_REG(0))) > 0) { + for (i = 0; i < fifo_len; i++) { uint8_t byte = READ_PERI_REG(UART_FIFO_REG(0)); switch (ub.state) { case READ_WAIT_START: { if (byte == 0xc0) { - ub.state = READ_DATA; + ub.state = READ_FLAGS; ub.ps = 0; } break; } + case READ_FLAGS: case READ_DATA: { + struct data_buf *buf = &ub.bufs[ub.bwi]; if (byte == 0xdb) { ub.state = READ_UNESCAPE; } else if (byte == 0xc0) { + next_write_buf(); if (ub.ps == 0) { - /* Empty packet, sender is done. */ + /* Empty packet, sender aborted. */ ub.state = READ_ERROR; SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0); goto out; @@ -155,9 +162,12 @@ void uart_isr(void *arg) { ub.state = READ_WAIT_START; } } else { - *ub.pw++ = byte; - ub.nr++; - ub.ps++; + if (ub.state == READ_FLAGS) { + buf->flags = byte; + ub.state = READ_DATA; + } else { + add_byte(byte); + } } break; } @@ -171,9 +181,7 @@ void uart_isr(void *arg) { SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0); goto out; } - *ub.pw++ = byte; - ub.nr++; - ub.ps++; + add_byte(byte); ub.state = READ_DATA; break; } @@ -182,13 +190,50 @@ void uart_isr(void *arg) { } } } - if (ub.pw == ub.pe) ub.pw = ub.data; } out: WRITE_PERI_REG(UART_INT_CLR_REG(0), int_st); (void) arg; } +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +#define TINFL_FLAG_PARSE_ZLIB_HEADER 1 + +#if defined(ESP8266) +int esp_rom_spiflash_erase_start(uint32_t addr, uint32_t cmd) { + SPI_write_enable(flashchip); + WRITE_PERI_REG(SPI_ADDR_REG(0), addr); + WRITE_PERI_REG(SPI_CMD_REG(0), cmd); + while (READ_PERI_REG(SPI_CMD_REG(0)) & cmd) { + } + return 0; +} +#elif defined(ESP32) +extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; + +esp_rom_spiflash_result_t esp_rom_spiflash_erase_start(uint32_t addr, + uint32_t cmd) { + esp_rom_spiflash_chip_t *spi = &g_rom_spiflash_chip; + esp_rom_spiflash_wait_idle(spi); + + REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY); + REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN, + ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN); + + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_WREN); + while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0) { + } + + WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, addr); + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, cmd); + + return ESP_ROM_SPIFLASH_RESULT_OK; +} +#endif + int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { int ret = 0; uint32_t num_erased = 0; @@ -199,10 +244,8 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { if (len % FLASH_SECTOR_SIZE != 0) return 0x33; if (esp_rom_spiflash_unlock() != 0) return 0x34; - ub.state = READ_WAIT_START; - ub.nr = 0; - ub.pr = ub.pw = ub.data; - ub.pe = ub.data + UART_BUF_SIZE; + memset(&ub, 0, sizeof(ub)); + memset(&inflate_buf, 0, sizeof(inflate_buf)); ets_isr_attach(ETS_UART0_INUM, uart_isr, &ub); uint32_t saved_conf1 = READ_PERI_REG(UART_CONF1_REG(0)); /* Reduce frequency of UART interrupts */ @@ -215,24 +258,24 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { struct write_result wr; memset(&wr, 0, sizeof(wr)); - struct write_progress wp = {.num_written = 0, .buf_level = ub.nr}; + struct write_progress wp = {.num_written = 0, .buf_level = 0}; + wp.buf_level = (uint32_t) &addr; SLIP_send(&wp, sizeof(wp)); wr.total_time = ccount(); while (wp.num_written < len) { - volatile uint32_t *nr = &ub.nr; /* Prepare the space ahead. */ uint32_t start_count = ccount(); while (erase && num_erased < wp.num_written + FLASH_WRITE_SIZE) { const uint32_t num_left = (len - num_erased); if (num_left >= FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) { - if (esp_rom_spiflash_erase_block(addr / FLASH_BLOCK_SIZE) != 0) { + if (esp_rom_spiflash_erase_start(addr, SPI_FLASH_BE) != 0) { ret = 0x35; goto out; } num_erased += FLASH_BLOCK_SIZE; } else { /* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */ - if (esp_rom_spiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) { + if (esp_rom_spiflash_erase_start(addr, SPI_FLASH_SE) != 0) { ret = 0x36; goto out; } @@ -242,29 +285,45 @@ int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { wr.erase_time += ccount() - start_count; start_count = ccount(); /* Wait for data to arrive. */ - wp.buf_level = *nr; - while (*nr < FLASH_WRITE_SIZE && ub.state != READ_ERROR) { + wp.buf_level = 0; + for (int i = 0; i < NUM_BUFS; i++) wp.buf_level += ub.bufs[i].len; + volatile uint32_t *bwi = &ub.bwi; + while (*bwi == ub.bri && ub.state != READ_ERROR) { } + struct data_buf *buf = &ub.bufs[ub.bri]; if (ub.state == READ_ERROR) { ret = 0x37; goto out; } wr.wait_time += ccount() - start_count; - MD5Update(&ctx, ub.pr, FLASH_WRITE_SIZE); start_count = ccount(); - if (esp_rom_spiflash_write(addr, (uint32_t *) ub.pr, FLASH_WRITE_SIZE) != - 0) { + uint32_t *data = (uint32_t *) buf->data; + uint32_t write_len = buf->len; + if (buf->flags & FLAG_COMPRESSED) { + data = inflate_buf; + write_len = tinfl_decompress_mem_to_mem( + &inflate_buf[0], sizeof(inflate_buf), buf->data, write_len, + TINFL_FLAG_PARSE_ZLIB_HEADER); + if (write_len == TINFL_DECOMPRESS_MEM_TO_MEM_FAILED) { + ret = 0x40; + goto out; + } + } + wr.decomp_time += ccount() - start_count; + MD5Update(&ctx, (uint8_t *) data, write_len); + start_count = ccount(); + wr.erase_time += ccount() - start_count; + start_count = ccount(); + if (esp_rom_spiflash_write(addr, data, write_len) != 0) { ret = 0x38; goto out; } wr.write_time += ccount() - start_count; - ets_intr_lock(); - *nr -= FLASH_WRITE_SIZE; - ets_intr_unlock(); - addr += FLASH_WRITE_SIZE; - ub.pr += FLASH_WRITE_SIZE; - if (ub.pr >= ub.data + UART_BUF_SIZE) ub.pr = ub.data; - wp.num_written += FLASH_WRITE_SIZE; + buf->len = 0; + ub.bri++; + if (ub.bri == NUM_BUFS) ub.bri = 0; + addr += write_len; + wp.num_written += write_len; struct MD5Context ctx2; memcpy(&ctx2, &ctx, sizeof(ctx)); MD5Final(wp.digest, &ctx2); @@ -349,7 +408,7 @@ int do_flash_read_chip_id(void) { } uint8_t cmd_loop(void) { - uint8_t cmd; + uint8_t cmd = 0x55; do { /* Reset FIFO to re-sync */ SET_PERI_REG_MASK(UART_CONF0_REG(0), UART_RXFIFO_RST); @@ -361,15 +420,6 @@ uint8_t cmd_loop(void) { } uint8_t resp = 0xff; switch (cmd) { - case CMD_FLASH_ERASE: { - len = SLIP_recv(args, sizeof(args)); - if (len == 8) { - resp = do_flash_erase(args[0] /* addr */, args[1] /* len */); - } else { - resp = 0x31; - } - break; - } case CMD_FLASH_WRITE: { len = SLIP_recv(args, sizeof(args)); if (len == 12) { @@ -427,7 +477,7 @@ uint8_t cmd_loop(void) { return cmd; } -void stub_main(void) { +void stub_main1(void) { uint32_t baud_rate = params[0]; uint32_t greeting = 0x4941484f; /* OHAI */ uint8_t last_cmd; @@ -435,8 +485,6 @@ void stub_main(void) { /* This points at us right now, reset for next boot. */ ets_set_user_start(0); - memset(&_bss_start, 0, (&_bss_end - &_bss_start)); - /* Selects SPI functions for flash pins. */ #if defined(ESP8266) SelectSpiFunction(); @@ -503,3 +551,15 @@ void stub_main(void) { } /* Not reached */ } + +/* miniz requires at least 12K of stack */ +uint32_t stack[3071]; +uint32_t stack_end; + +void stub_main(void) { + memset(&_bss_start, 0, (&_bss_end - &_bss_start)); + __asm volatile("movi a1, stack_end\n"); + stub_main1(); + // Keep the stack vars alive. + stack[0] = stack_end = 0xff; +} diff --git a/common/platforms/esp/stub_flasher.h b/common/platforms/esp/stub_flasher.h index ccff848..4bae4c6 100644 --- a/common/platforms/esp/stub_flasher.h +++ b/common/platforms/esp/stub_flasher.h @@ -2,15 +2,6 @@ #define CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_ enum stub_cmd { - /* - * Erase a region of SPI flash. - * - * Args: addr, len; must be FLASH_SECTOR_SIZE-aligned. - * Input: None. - * Output: None. - */ - CMD_FLASH_ERASE = 0, - /* * Write to the SPI flash. * diff --git a/common/platforms/esp8266/rom/ESP8266_ROM.txt b/common/platforms/esp8266/rom/ESP8266_ROM.txt index d4287cf..5e638f9 100644 --- a/common/platforms/esp8266/rom/ESP8266_ROM.txt +++ b/common/platforms/esp8266/rom/ESP8266_ROM.txt @@ -181,8 +181,14 @@ Disassembly of section .text: 4000040f: fe .byte 0xfe 40000410: 800000 add a0, a0, a0 40000413: 7f .byte 0x7f + +40000414 <_c_0x00400000>: 40000414: 400000 ssr a0 -40000417: ffff00 excw + ... + +40000418 <_c_0x00ffffff>: +40000418: ff .byte 0xff +40000419: ff .byte 0xff 4000041a: ff .byte 0xff 4000041b: 000000 ill 4000041e: 007ff0 excw @@ -199,13 +205,13 @@ Disassembly of section .text: 40000436: 002010 rsync 40000439: ffd261 l32r a6, 40000384 <_ResetHandler+0x2e0> 4000043c: ffd371 l32r a7, 40000388 <_ResetHandler+0x2e4> -4000043f: 06b677 bgeu a6, a7, 40000449 <_c_0x80000000+0xa5> +4000043f: 06b677 bgeu a6, a7, 40000449 <_c_0x00ffffff+0x31> 40000442: 0609 s32i.n a0, a6, 0 40000444: 664b addi.n a6, a6, 4 -40000446: f83677 bltu a6, a7, 40000442 <_c_0x80000000+0x9e> +40000446: f83677 bltu a6, a7, 40000442 <_c_0x00ffffff+0x2a> 40000449: 00ba05 call0 40000fec
4000044c: 0041f0 break 1, 15 -4000044f: fffe46 j 4000044c <_c_0x80000000+0xa8> +4000044f: fffe46 j 4000044c <_c_0x00ffffff+0x34> ... 40000454 <_xtos_set_exception_handler>: @@ -6596,7 +6602,7 @@ Disassembly of section .text: 40004085: 0109 s32i.n a0, a1, 0 40004087: 02cd mov.n a12, a2 40004089: 004005 call0 4000448c -4000408c: f0e231 l32r a3, 40000414 <_c_0x80000000+0x70> +4000408c: f0e231 l32r a3, 40000414 <_c_0x00400000> 4000408f: f3cd01 l32r a0, 40000fc4 <_c_0x60000200> 40004092: 0020c0 memw 40004095: 0039 s32i.n a3, a0, 0 @@ -6613,36 +6619,44 @@ Disassembly of section .text: 400040b4: 0108 l32i.n a0, a1, 0 400040b6: 10c112 addi a1, a1, 16 400040b9: f00d ret.n -400040bb: 000000 ill -400040be: 120100 excw -400040c1: 29f0c1 l32r a12, 3ffce884 -400040c4: 21c901 l32r a0, 3ffcc7e8 + ... + +400040bc <_c_0x01000000>: +400040bc: 000000 ill +400040bf: c11201 l32r a0, 3fff4508 + +400040c0 <_x_SPI_erase_sector>: +400040c0: f0c112 addi a1, a1, -16 +400040c3: 0129 s32i.n a2, a1, 0 +400040c5: 21c9 s32i.n a12, a1, 8 400040c7: 1109 s32i.n a0, a1, 4 400040c9: 03cd mov.n a12, a3 400040cb: b40030 extui a0, a3, 0, 12 -400040ce: a08c beqz.n a0, 400040dc +400040ce: a08c beqz.n a0, 400040dc <_l_SPI_erase_sector_align_ok> 400040d0: 120c movi.n a2, 1 400040d2: 21c8 l32i.n a12, a1, 8 400040d4: 1108 l32i.n a0, a1, 4 400040d6: 10c112 addi a1, a1, 16 400040d9: f00d ret.n -400040db: 3ac500 excw -400040de: 210200 srai a0, a0, 2 -400040e1: cd5100 excw -400040e4: b721f0 excw -400040e7: 5c50f3 excw -400040ea: 20c010 or a12, a0, a1 -400040ed: 625200 excw -400040f0: f24101 l32r a0, 400009f4 -400040f3: ff .byte 0xff + ... + +400040dc <_l_SPI_erase_sector_align_ok>: +400040dc: 003ac5 call0 4000448c +400040df: 002102 l32i a0, a1, 0 +400040e2: f0cd51 l32r a5, 40000418 <_c_0x00ffffff> +400040e5: f3b721 l32r a2, 40000fc4 <_c_0x60000200> +400040e8: 105c50 and a5, a12, a5 +400040eb: 0020c0 memw +400040ee: 016252 s32i a5, a2, 4 +400040f1: fff241 l32r a4, 400040bc <_c_0x01000000> 400040f4: 0020c0 memw 400040f7: 006242 s32i a4, a2, 0 400040fa: 0020c0 memw 400040fd: 0238 l32i.n a3, a2, 0 -400040ff: 638c beqz.n a3, 40004109 +400040ff: 638c beqz.n a3, 40004109 <_l_SPI_erase_sector_align_ok+0x2d> 40004101: 0020c0 memw 40004104: 0268 l32i.n a6, a2, 0 -40004106: ff7656 bnez a6, 40004101 +40004106: ff7656 bnez a6, 40004101 <_l_SPI_erase_sector_align_ok+0x25> 40004109: 202000 or a2, a0, a0 4000410c: 0037c5 call0 4000448c 4000410f: 00a022 movi a2, 0 @@ -6650,28 +6664,33 @@ Disassembly of section .text: 40004115: 1108 l32i.n a0, a1, 4 40004117: 10c112 addi a1, a1, 16 4000411a: f00d ret.n + +4000411c <_c_0x00800000>: 4000411c: 800000 add a0, a0, a0 -4000411f: c11200 mul16u a1, a2, a0 -40004122: 6132f0 excw -40004125: 61c200 xsr.eps2 a0 -40004128: 610202 l8ui a0, a2, 97 -4000412b: 02cd01 l32r a0, 3ffc4c60 + ... + +40004120 <_x_SPI_erase_block>: +40004120: f0c112 addi a1, a1, -16 +40004123: 006132 s32i a3, a1, 0 +40004126: 0261c2 s32i a12, a1, 8 +40004129: 016102 s32i a0, a1, 4 +4000412c: 02cd mov.n a12, a2 4000412e: 0035c5 call0 4000448c -40004131: f0b951 l32r a5, 40000418 <_c_0x80000000+0x74> +40004131: f0b951 l32r a5, 40000418 <_c_0x00ffffff> 40004134: 0148 l32i.n a4, a1, 0 40004136: f3a301 l32r a0, 40000fc4 <_c_0x60000200> 40004139: 104450 and a4, a4, a5 4000413c: 0020c0 memw 4000413f: 1049 s32i.n a4, a0, 4 -40004141: fff631 l32r a3, 4000411c +40004141: fff631 l32r a3, 4000411c <_c_0x00800000> 40004144: 0020c0 memw 40004147: 0039 s32i.n a3, a0, 0 40004149: 0020c0 memw 4000414c: 0028 l32i.n a2, a0, 0 -4000414e: 628c beqz.n a2, 40004158 +4000414e: 628c beqz.n a2, 40004158 <_x_SPI_erase_block+0x38> 40004150: 0020c0 memw 40004153: 0068 l32i.n a6, a0, 0 -40004155: ff7656 bnez a6, 40004150 +40004155: ff7656 bnez a6, 40004150 <_x_SPI_erase_block+0x30> 40004158: 202cc0 or a2, a12, a12 4000415b: 003305 call0 4000448c 4000415e: 00a022 movi a2, 0 @@ -6718,7 +6737,7 @@ Disassembly of section .text: 400041bc: 021ee6 bgei a14, 1, 400041c2 <_c_0x20000000+0x56> 400041bf: 003586 j 40004299 <_c_0x20000000+0x12d> 400041c2: f380c1 l32r a12, 40000fc4 <_c_0x60000200> -400041c5: f09401 l32r a0, 40000418 <_c_0x80000000+0x74> +400041c5: f09401 l32r a0, 40000418 <_c_0x00ffffff> 400041c8: 001a06 j 40004234 <_c_0x20000000+0xc8> 400041cb: e83100 excw 400041ce: ff .byte 0xff @@ -6757,7 +6776,7 @@ Disassembly of section .text: 40004225: ff7956 bnez a9, 40004220 <_c_0x20000000+0xb4> 40004228: 062122 l32i a2, a1, 24 4000422b: 002605 call0 4000448c -4000422e: f07a01 l32r a0, 40000418 <_c_0x80000000+0x74> +4000422e: f07a01 l32r a0, 40000418 <_c_0x00ffffff> 40004231: 641ea6 blti a14, 1, 40004299 <_c_0x20000000+0x12d> 40004234: 107f00 and a7, a15, a0 40004237: 91cee6 bgei a14, 32, 400041cc <_c_0x20000000+0x60> @@ -7034,7 +7053,7 @@ Disassembly of section .text: 400044c0: f0c112 addi a1, a1, -16 400044c3: 0109 s32i.n a0, a1, 0 400044c5: 11c9 s32i.n a12, a1, 4 -400044c7: efd331 l32r a3, 40000414 <_c_0x80000000+0x70> +400044c7: efd331 l32r a3, 40000414 <_c_0x00400000> 400044ca: 02cd mov.n a12, a2 400044cc: f2be21 l32r a2, 40000fc4 <_c_0x60000200> 400044cf: 0020c0 memw @@ -7062,7 +7081,7 @@ Disassembly of section .text: 40004506: 120000 excw 40004509: 09f0c1 l32r a12, 3ffc6ccc 4000450c: 21c911 l32r a1, 3ffccc30 -4000450f: efc131 l32r a3, 40000414 <_c_0x80000000+0x70> +4000450f: efc131 l32r a3, 40000414 <_c_0x00400000> 40004512: 02cd mov.n a12, a2 40004514: f2ac21 l32r a2, 40000fc4 <_c_0x60000200> 40004517: 0020c0 memw @@ -7276,7 +7295,7 @@ Disassembly of section .text: 40004724: 102250 and a2, a2, a5 40004727: 0020c0 memw 4000472a: 836722 s32i a2, a7, 0x20c -4000472d: fe63b1 l32r a11, 400040bc +4000472d: fe63b1 l32r a11, 400040bc <_c_0x01000000> 40004730: 0020c0 memw 40004733: 8327a2 l32i a10, a7, 0x20c 40004736: 20aab0 or a10, a10, a11 @@ -7391,11 +7410,13 @@ Disassembly of section .text: 4000486c: 836382 s32i a8, a3, 0x20c 4000486f: f00d ret.n 40004871: 000000 ill + +40004874 <_p_flashchip>: 40004874: ffc714 excw 40004877: 3f .byte 0x3f 40004878 : -40004878: ffff21 l32r a2, 40004874 +40004878: ffff21 l32r a2, 40004874 <_p_flashchip> 4000487b: f0c112 addi a1, a1, -16 4000487e: 0109 s32i.n a0, a1, 0 40004880: 002222 l32i a2, a2, 0 @@ -7405,7 +7426,7 @@ Disassembly of section .text: 4000488a: 0108 l32i.n a0, a1, 0 4000488c: 10c112 addi a1, a1, 16 4000488f: f00d ret.n -40004891: fff821 l32r a2, 40004874 +40004891: fff821 l32r a2, 40004874 <_p_flashchip> 40004894: 030c movi.n a3, 0 40004896: 002222 l32i a2, a2, 0 40004899: ffb645 call0 40004400 @@ -7416,7 +7437,7 @@ Disassembly of section .text: 400048a6: f00d ret.n 400048a8 : -400048a8: fff321 l32r a2, 40004874 +400048a8: fff321 l32r a2, 40004874 <_p_flashchip> 400048ab: f0c112 addi a1, a1, -16 400048ae: 0109 s32i.n a0, a1, 0 400048b0: 002222 l32i a2, a2, 0 @@ -7426,7 +7447,7 @@ Disassembly of section .text: 400048ba: 0108 l32i.n a0, a1, 0 400048bc: 10c112 addi a1, a1, 16 400048bf: f00d ret.n -400048c1: ffec21 l32r a2, 40004874 +400048c1: ffec21 l32r a2, 40004874 <_p_flashchip> 400048c4: c31c movi.n a3, 28 400048c6: 002222 l32i a2, a2, 0 400048c9: ffb345 call0 40004400 @@ -7450,7 +7471,7 @@ Disassembly of section .text: 400048ec: f0c112 addi a1, a1, -16 400048ef: 1109 s32i.n a0, a1, 4 400048f1: fff941 l32r a4, 400048d8 -400048f4: ffe051 l32r a5, 40004874 +400048f4: ffe051 l32r a5, 40004874 <_p_flashchip> 400048f7: f1b301 l32r a0, 40000fc4 <_c_0x60000200> 400048fa: 0020c0 memw 400048fd: 2038 l32i.n a3, a0, 8 @@ -7508,7 +7529,7 @@ Disassembly of section .text: 40004981: 000000 ill 40004984 : -40004984: ffbc21 l32r a2, 40004874 +40004984: ffbc21 l32r a2, 40004874 <_p_flashchip> 40004987: f0c112 addi a1, a1, -16 4000498a: 0109 s32i.n a0, a1, 0 4000498c: 002222 l32i a2, a2, 0 @@ -7518,7 +7539,7 @@ Disassembly of section .text: 40004996: 0108 l32i.n a0, a1, 0 40004998: 10c112 addi a1, a1, 16 4000499b: f00d ret.n -4000499d: ffb521 l32r a2, 40004874 +4000499d: ffb521 l32r a2, 40004874 <_p_flashchip> 400049a0: 0020f0 nop 400049a3: 0228 l32i.n a2, a2, 0 400049a5: ff6d85 call0 40004080 @@ -7529,7 +7550,7 @@ Disassembly of section .text: 400049b2: f00d ret.n 400049b4 : -400049b4: ffb031 l32r a3, 40004874 +400049b4: ffb031 l32r a3, 40004874 <_p_flashchip> 400049b7: f0c112 addi a1, a1, -16 400049ba: 21c9 s32i.n a12, a1, 8 400049bc: 1109 s32i.n a0, a1, 4 @@ -7548,11 +7569,11 @@ Disassembly of section .text: 400049da: 0128 l32i.n a2, a1, 0 400049dc: ffa5c5 call0 4000443c 400049df: fec256 bnez a2, 400049cf -400049e2: ffa421 l32r a2, 40004874 +400049e2: ffa421 l32r a2, 40004874 <_p_flashchip> 400049e5: 0228 l32i.n a2, a2, 0 400049e7: 022232 l32i a3, a2, 8 400049ea: 8233c0 mull a3, a3, a12 -400049ed: ff7305 call0 40004120 +400049ed: ff7305 call0 40004120 <_x_SPI_erase_block> 400049f0: fdb256 bnez a2, 400049cf 400049f3: 020c movi.n a2, 0 400049f5: 21c8 l32i.n a12, a1, 8 @@ -7562,7 +7583,7 @@ Disassembly of section .text: ... 40004a00 : -40004a00: ff9d31 l32r a3, 40004874 +40004a00: ff9d31 l32r a3, 40004874 <_p_flashchip> 40004a03: f0c112 addi a1, a1, -16 40004a06: 21c9 s32i.n a12, a1, 8 40004a08: 1109 s32i.n a0, a1, 4 @@ -7581,11 +7602,11 @@ Disassembly of section .text: 40004a26: 0128 l32i.n a2, a1, 0 40004a28: ffa105 call0 4000443c 40004a2b: fec256 bnez a2, 40004a1b -40004a2e: ff9121 l32r a2, 40004874 +40004a2e: ff9121 l32r a2, 40004874 <_p_flashchip> 40004a31: 0228 l32i.n a2, a2, 0 40004a33: 032232 l32i a3, a2, 12 40004a36: 8233c0 mull a3, a3, a12 -40004a39: ff6845 call0 400040c0 +40004a39: ff6845 call0 400040c0 <_x_SPI_erase_sector> 40004a3c: fdb256 bnez a2, 40004a1b 40004a3f: 020c movi.n a2, 0 40004a41: 21c8 l32i.n a12, a1, 8 @@ -7596,7 +7617,7 @@ Disassembly of section .text: 40004a4c : 40004a4c: 045d mov.n a5, a4 -40004a4e: ff8981 l32r a8, 40004874 +40004a4e: ff8981 l32r a8, 40004874 <_p_flashchip> 40004a51: d0c112 addi a1, a1, -48 40004a54: 31c9 s32i.n a12, a1, 12 40004a56: 51e9 s32i.n a14, a1, 20 @@ -7658,7 +7679,7 @@ Disassembly of section .text: 40004ad3: 076132 s32i a3, a1, 28 40004ad6: 3dca add.n a3, a13, a12 40004ad8: 0e5d mov.n a5, a14 -40004ada: ff6621 l32r a2, 40004874 +40004ada: ff6621 l32r a2, 40004874 <_p_flashchip> 40004add: 4142c0 srli a4, a12, 2 40004ae0: a044f0 addx4 a4, a4, a15 40004ae3: 0228 l32i.n a2, a2, 0 @@ -7672,7 +7693,7 @@ Disassembly of section .text: 40004af8: 7169 s32i.n a6, a1, 28 40004afa: d89567 bne a5, a6, 40004ad6 40004afd: 3dca add.n a3, a13, a12 -40004aff: ff5d21 l32r a2, 40004874 +40004aff: ff5d21 l32r a2, 40004874 <_p_flashchip> 40004b02: 002152 l32i a5, a1, 0 40004b05: 4142c0 srli a4, a12, 2 40004b08: a044f0 addx4 a4, a4, a15 @@ -7689,7 +7710,7 @@ Disassembly of section .text: 40004b20: f0c112 addi a1, a1, -16 40004b23: 023d mov.n a3, a2 40004b25: 0109 s32i.n a0, a1, 0 -40004b27: ff5321 l32r a2, 40004874 +40004b27: ff5321 l32r a2, 40004874 <_p_flashchip> 40004b2a: 074d mov.n a4, a7 40004b2c: 0228 l32i.n a2, a2, 0 40004b2e: ff77c5 call0 400042ac <_c_0x20000000+0x140> @@ -7712,7 +7733,7 @@ Disassembly of section .text: 40004b4f: 20d330 or a13, a3, a3 40004b52: 05a022 movi a2, 5 40004b55: ffd945 call0 400048ec -40004b58: ff4701 l32r a0, 40004874 +40004b58: ff4701 l32r a0, 40004874 <_p_flashchip> 40004b5b: 0008 l32i.n a0, a0, 0 40004b5d: 4109 s32i.n a0, a1, 16 40004b5f: 1008 l32i.n a0, a0, 4 @@ -7732,7 +7753,7 @@ Disassembly of section .text: 40004b80: 4128 l32i.n a2, a1, 16 40004b82: ffcf45 call0 40004878 40004b85: fdd256 bnez a2, 40004b66 -40004b88: ff3b31 l32r a3, 40004874 +40004b88: ff3b31 l32r a3, 40004874 <_p_flashchip> 40004b8b: 0c2d mov.n a2, a12 40004b8d: 0338 l32i.n a3, a3, 0 40004b8f: 4139 s32i.n a3, a1, 16 @@ -7802,7 +7823,7 @@ Disassembly of section .text: 40004c29: 000000 ill 40004c2c : -40004c2c: ff1281 l32r a8, 40004874 +40004c2c: ff1281 l32r a8, 40004874 <_p_flashchip> 40004c2f: 0888 l32i.n a8, a8, 0 40004c31: 1839 s32i.n a3, a8, 4 40004c33: 2849 s32i.n a4, a8, 8 @@ -8915,7 +8936,7 @@ Disassembly of section .text: 400056fd: f938 l32i.n a3, a9, 60 400056ff: 025d mov.n a5, a2 40005701: 0fc216 beqz a2, 40005801 -40005704: eb4571 l32r a7, 40000418 <_c_0x80000000+0x74> +40005704: eb4571 l32r a7, 40000418 <_c_0x00ffffff> 40005707: 000c movi.n a0, 0 40005709: 0020c0 memw 4000570c: 011542 l16ui a4, a5, 2 @@ -9345,7 +9366,7 @@ Disassembly of section .text: 40005b54: 0020c0 memw 40005b57: 001262 l16ui a6, a2, 0 40005b5a: 204460 or a4, a4, a6 -40005b5d: ea2e61 l32r a6, 40000418 <_c_0x80000000+0x74> +40005b5d: ea2e61 l32r a6, 40000418 <_c_0x00ffffff> 40005b60: 104460 and a4, a4, a6 40005b63: 414c40 srli a4, a4, 12 40005b66: 445a add.n a4, a4, a5 @@ -9521,7 +9542,7 @@ Disassembly of section .text: 40005d1b: 207780 or a7, a7, a8 40005d1e: 0020c0 memw 40005d21: 576c72 s32i a7, a12, 0x15c -40005d24: f8fe61 l32r a6, 4000411c +40005d24: f8fe61 l32r a6, 4000411c <_c_0x00800000> 40005d27: 0020c0 memw 40005d2a: 6d6c62 s32i a6, a12, 0x1b4 40005d2d: 0020c0 memw @@ -11726,7 +11747,7 @@ Disassembly of section .text: 400072db: 117480 slli a7, a4, 8 400072de: f31d91 l32r a9, 40003f54 <_c_0x60000a00> 400072e1: 207780 or a7, a7, a8 -400072e4: f37681 l32r a8, 400040bc +400072e4: f37681 l32r a8, 400040bc <_c_0x01000000> 400072e7: 207270 or a7, a2, a7 400072ea: 207780 or a7, a7, a8 400072ed: 1183e0 slli a8, a3, 2 @@ -19748,7 +19769,7 @@ Disassembly of section .text: 4000c3a2: 003406 j 4000c476 <__mulsf3+0x9a> 4000c3a5: 1183f0 slli a8, a3, 1 4000c3a8: 88cc bnez.n a8, 4000c3b4 <__subsf3+0x14c> -4000c3aa: d01a41 l32r a4, 40000414 <_c_0x80000000+0x70> +4000c3aa: d01a41 l32r a4, 40000414 <_c_0x00400000> 4000c3ad: 202240 or a2, a2, a4 4000c3b0: 003086 j 4000c476 <__mulsf3+0x9a> 4000c3b3: c36700 excw @@ -19762,7 +19783,7 @@ Disassembly of section .text: 4000c3ca: 002a06 j 4000c476 <__mulsf3+0x9a> 4000c3cd: 1182f0 slli a8, a2, 1 4000c3d0: fe8856 bnez a8, 4000c3bc <__subsf3+0x154> -4000c3d3: d01071 l32r a7, 40000414 <_c_0x80000000+0x70> +4000c3d3: d01071 l32r a7, 40000414 <_c_0x00400000> 4000c3d6: 202370 or a2, a3, a7 4000c3d9: 002646 j 4000c476 <__mulsf3+0x9a> @@ -19781,7 +19802,7 @@ Disassembly of section .text: 4000c3f9: f67816 beqz a8, 4000c364 <__subsf3+0xfc> 4000c3fc: f80916 beqz a9, 4000c380 <__subsf3+0x118> 4000c3ff: 889a add.n a8, a8, a9 -4000c401: d005a1 l32r a10, 40000418 <_c_0x80000000+0x74> +4000c401: d005a1 l32r a10, 40000418 <_c_0x00ffffff> 4000c404: 202260 or a2, a2, a6 4000c407: 1022a0 and a2, a2, a10 4000c40a: 203360 or a3, a3, a6 @@ -19902,7 +19923,7 @@ Disassembly of section .text: 4000c535: 000000 ill 4000c538 <__adddf3>: -4000c538: cfb961 l32r a6, 4000041c <_c_0x80000000+0x78> +4000c538: cfb961 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000c53b: 307350 xor a7, a3, a5 4000c53e: fea796 bltz a7, 4000c52c <__fixunssfsi+0x68> 4000c541: d34367 ball a3, a6, 4000c518 <__fixunssfsi+0x54> @@ -20015,7 +20036,7 @@ Disassembly of section .text: 4000c660: 331b addi.n a3, a3, 1 4000c662: f00d ret.n 4000c664: 05c567 bnall a5, a6, 4000c66d <__adddf3+0x135> -4000c667: cf6e41 l32r a4, 40000420 <_c_0x80000000+0x7c> +4000c667: cf6e41 l32r a4, 40000420 <_c_0x00ffffff+0x8> 4000c66a: 203340 or a3, a3, a4 4000c66d: f00d ret.n 4000c66f: 765000 excw @@ -20030,7 +20051,7 @@ Disassembly of section .text: 4000c685: 000000 ill 4000c688 <__subdf3>: -4000c688: cf6561 l32r a6, 4000041c <_c_0x80000000+0x78> +4000c688: cf6561 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000c68b: 307350 xor a7, a3, a5 4000c68e: fea796 bltz a7, 4000c67c <__adddf3+0x144> 4000c691: cf4367 ball a3, a6, 4000c664 <__adddf3+0x12c> @@ -20230,7 +20251,7 @@ Disassembly of section .text: 4000c8ac: d4cc bnez.n a4, 4000c8bd <__subdf3+0x235> 4000c8ae: 1185f0 slli a8, a5, 1 4000c8b1: 88cc bnez.n a8, 4000c8bd <__subdf3+0x235> -4000c8b3: cedb41 l32r a4, 40000420 <_c_0x80000000+0x7c> +4000c8b3: cedb41 l32r a4, 40000420 <_c_0x00ffffff+0x8> 4000c8b6: 203340 or a3, a3, a4 4000c8b9: 006046 j 4000ca3e <__muldf3+0x14e> 4000c8bc: c56700 extui a6, a0, 23, 13 @@ -20249,7 +20270,7 @@ Disassembly of section .text: 4000c8de: fe .byte 0xfe 4000c8df: 1183f0 slli a8, a3, 1 4000c8e2: fe2856 bnez a8, 4000c8c8 <__subdf3+0x240> -4000c8e5: cece71 l32r a7, 40000420 <_c_0x80000000+0x7c> +4000c8e5: cece71 l32r a7, 40000420 <_c_0x00ffffff+0x8> 4000c8e8: 203570 or a3, a5, a7 4000c8eb: 0053c6 j 4000ca3e <__muldf3+0x14e> ... @@ -20260,7 +20281,7 @@ Disassembly of section .text: 4000c8f5: 51d9 s32i.n a13, a1, 20 4000c8f7: 61e9 s32i.n a14, a1, 24 4000c8f9: 71f9 s32i.n a15, a1, 28 -4000c8fb: cec861 l32r a6, 4000041c <_c_0x80000000+0x78> +4000c8fb: cec861 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000c8fe: 307350 xor a7, a3, a5 4000c901: a74367 ball a3, a6, 4000c8ac <__subdf3+0x224> 4000c904: d44567 ball a5, a6, 4000c8dc <__subdf3+0x254> @@ -20269,7 +20290,7 @@ Disassembly of section .text: 4000c90d: eff816 beqz a8, 4000c810 <__subdf3+0x188> 4000c910: f45916 beqz a9, 4000c859 <__subdf3+0x1d1> 4000c913: 889a add.n a8, a8, a9 -4000c915: cec3a1 l32r a10, 40000424 <_c_0x80000000+0x80> +4000c915: cec3a1 l32r a10, 40000424 <_c_0x00ffffff+0xc> 4000c918: 203360 or a3, a3, a6 4000c91b: 1033a0 and a3, a3, a10 4000c91e: 205560 or a5, a5, a6 @@ -20454,7 +20475,7 @@ Disassembly of section .text: 4000caff: 331005 call0 4003fc00 <__bss_start+0x2fc00> 4000cb02: 336001 l32r a0, 3ffd9884 4000cb05: 42cc20 excw -4000cb08: ce4641 l32r a4, 40000420 <_c_0x80000000+0x7c> +4000cb08: ce4641 l32r a4, 40000420 <_c_0x00ffffff+0x8> 4000cb0b: 203340 or a3, a3, a4 4000cb0e: 020c movi.n a2, 0 4000cb10: f00d ret.n @@ -20508,7 +20529,7 @@ Disassembly of section .text: 4000cb91: 000000 ill 4000cb94 <__divdf3>: -4000cb94: ce2261 l32r a6, 4000041c <_c_0x80000000+0x78> +4000cb94: ce2261 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000cb97: 307350 xor a7, a3, a5 4000cb9a: ca4367 ball a3, a6, 4000cb68 <__muldf3+0x278> 4000cb9d: db4567 ball a5, a6, 4000cb7c <__muldf3+0x28c> @@ -20517,7 +20538,7 @@ Disassembly of section .text: 4000cba6: f02916 beqz a9, 4000caac <__muldf3+0x1bc> 4000cba9: f67816 beqz a8, 4000cb14 <__muldf3+0x224> 4000cbac: c08890 sub a8, a8, a9 -4000cbaf: ce1da1 l32r a10, 40000424 <_c_0x80000000+0x80> +4000cbaf: ce1da1 l32r a10, 40000424 <_c_0x00ffffff+0xc> 4000cbb2: 203360 or a3, a3, a6 4000cbb5: 1033a0 and a3, a3, a10 4000cbb8: 205560 or a5, a5, a6 @@ -20616,7 +20637,7 @@ Disassembly of section .text: ... 4000ccb8 <__fixdfsi>: -4000ccb8: cdd961 l32r a6, 4000041c <_c_0x80000000+0x78> +4000ccb8: cdd961 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000ccbb: 254367 ball a3, a6, 4000cce4 <__fixdfsi+0x2c> 4000ccbe: a54430 extui a4, a3, 20, 11 4000ccc1: 955360 extui a5, a6, 19, 10 @@ -20644,7 +20665,7 @@ Disassembly of section .text: 4000ccfe: f00d ret.n 4000cd00 <__fixunsdfsi>: -4000cd00: cdc761 l32r a6, 4000041c <_c_0x80000000+0x78> +4000cd00: cdc761 l32r a6, 4000041c <_c_0x00ffffff+0x4> 4000cd03: 2a4367 ball a3, a6, 4000cd31 <__fixunsdfsi+0x31> 4000cd06: a54430 extui a4, a3, 20, 11 4000cd09: 955460 extui a5, a6, 20, 10 @@ -20681,7 +20702,7 @@ Disassembly of section .text: 4000cd59: 000000 ill 4000cd5c <__truncdfsf2>: -4000cd5c: cdb341 l32r a4, 40000428 <_c_0x80000000+0x84> +4000cd5c: cdb341 l32r a4, 40000428 <_c_0x00ffffff+0x10> 4000cd5f: c05340 sub a5, a3, a4 4000cd62: 306350 xor a6, a3, a5 4000cd65: 053696 bltz a6, 4000cdbc <__truncdfsf2+0x60> @@ -20746,7 +20767,7 @@ Disassembly of section .text: 4000ce0a: 661b addi.n a6, a6, 1 4000ce0c: 10f626 beqi a6, 0x100, 4000ce20 <__extendsfdf2+0x24> 4000ce0f: 414440 srli a4, a4, 4 -4000ce12: cd8561 l32r a6, 40000428 <_c_0x80000000+0x84> +4000ce12: cd8561 l32r a6, 40000428 <_c_0x00ffffff+0x10> 4000ce15: 012230 slli a2, a2, 29 4000ce18: 446a add.n a4, a4, a6 4000ce1a: 203450 or a3, a4, a5 diff --git a/common/platforms/esp8266/rom/rom.S b/common/platforms/esp8266/rom/rom.S index 90c3fd2..784b486 100644 --- a/common/platforms/esp8266/rom/rom.S +++ b/common/platforms/esp8266/rom/rom.S @@ -13,6 +13,8 @@ PROVIDE(SPI_chip_erase, 0x40004080) PROVIDE(SPIFlashModeConfig, 0x40004568) PROVIDE(_c_0x80000000, 0x400003a4) +PROVIDE(_c_0x00400000, 0x40000414) +PROVIDE(_c_0x00ffffff, 0x40000418) PROVIDE(_p_user_start, 0x40000fb8) // 0x3fffdcd0 PROVIDE(_c_0x60000200, 0x40000fc4) PROVIDE(_s_ets_build, 0x40000fc8) // Jan 8 2013 @@ -76,10 +78,16 @@ PROVIDE(_l_34a3, 0x400034a3) PROVIDE(_l_34b9, 0x400034b9) PROVIDE(_c_0x00001800, 0x40003534) PROVIDE(_c_0x60000a00, 0x40003f54) +PROVIDE(_c_0x01000000, 0x400040bc) +PROVIDE(_x_SPI_erase_sector, 0x400040c0) +PROVIDE(_l_SPI_erase_sector_align_ok, 0x400040dc) +PROVIDE(_c_0x00800000, 0x4000411c) +PROVIDE(_x_SPI_erase_block, 0x40004120) PROVIDE(_c_0x20000000, 0x4000416c) PROVIDE(_c_0x08000000, 0x400043c4) PROVIDE(_c_0x04000000, 0x400043fc) PROVIDE(_c_0x40000000, 0x40004438) +PROVIDE(_p_flashchip, 0x40004874) PROVIDE(_s_bootup, 0x400054cc) // bootup , addr 0x%08x PROVIDE(_p_sip_ctx, 0x40005130) PROVIDE(_l_sip_cmd_out, 0x4000550a) diff --git a/common/platforms/esp8266/rom/rom.elf b/common/platforms/esp8266/rom/rom.elf index 65d4e6701dba1de4cf3c0b14a41dfadb81c22eb9..a9ceeb7a35acf7ddd9ea2cc36dc7735320772595 100755 GIT binary patch delta 1580 zcmZY7O-NKx7zW_))DUS4b+T#vSxja>E4`AYq>!nB2Es&E6ccxJ98(-qoQW)gTjU}N zBOw?i7e+z$1BGNNgalbe2uZjSDHjSE5iO!NLcMdRne$R-b)WZq_dDm~-q~-C`R|UK zo^=(am-EK*)Ek$T>5xjXmlB6d#7%a>6KQ(i15c9+;J4&*c$QoT&ykPA^W>mQELo!9 z9151nz3^vpKU|ZpFEk7vB9Fmm$un>-`6GOd{L^KLj8KrWRb+~s4ZAb+fxF;s%FdaT~i7aoLD6ShRj z0|fp=0FT3W_UIR0!BgaUc!9hE=NIexAMjoB8azpMWQ!D+#Ov|@D{&%d*smLS;1`wJ z1@KF96}(6`;oJkdz617TvnqSPQZ~`?bq;ZgZ6va zIIO(@rykW_g_llg|AKLDCC0WNWX%rZ1?jlZ`kX|8NX%*fST~68OJSs=t1u9#3LoqU z*N%_osMRgm0n_L)jAA3U#Eh%OUgLvBD${Y&D6;pk*<&8@)|tWX#&FOK2LqALZZSju zWoBcj?erP5vpvzR>~C*=y(!cgXpi16QTsM^nJuBlaBHBottz?KKUay%9xpa>>}$l=A5yo%rvLx| delta 1321 zcmZ9~O-NKx7zW_)#HAk#vZ2>Ep z#U?j2P&HX)W_@;gr-UWHj5t1#6xjpMk;~yU`4GH7J`QKd&2W}{1zsk1`ozi#1-&Rl ziuFQ+@EP(`xR*Qu50XE@_sC1|D0vN@A^-MS5&te7xP7lkCAka^k`Kd8N@CY6uzko-{6YyK|2lz924nFJA4_bh)k-x&7Wcvd_f`To6k%we2 z{GNOe-nv@{9D^U1sGHy~`_&iW>I3TQ@Kv>yE(Gm0TCnh*fcichBtL^2$nW6GLHVL>_{p;U)4sTkk2Th-m-- diff --git a/common/platforms/esp8266/stubs/Makefile b/common/platforms/esp8266/stubs/Makefile index 7dd2ce4..7aee561 100644 --- a/common/platforms/esp8266/stubs/Makefile +++ b/common/platforms/esp8266/stubs/Makefile @@ -6,6 +6,7 @@ STUB = stub_hello.c LIBS = PARAMS = +CFLAGS = PORT = /dev/ttyUSB0 BUILD_DIR = .build @@ -29,7 +30,7 @@ $(STUB_ELF): $(STUB) $(LIBS) -I. -I/src/common/platforms/esp \ -I/opt/Espressif/ESP8266_SDK \ -Wl,-static -ffunction-sections -Wl,--gc-sections \ - -Tstub.ld -o $@ $^" + -Tstub.ld $(CFLAGS) -o $@ $^" wrap: $(STUB_JSON) diff --git a/common/platforms/esp8266/stubs/rom_functions.h b/common/platforms/esp8266/stubs/rom_functions.h index b302b5f..82ea746 100644 --- a/common/platforms/esp8266/stubs/rom_functions.h +++ b/common/platforms/esp8266/stubs/rom_functions.h @@ -3,6 +3,9 @@ #include +#include "/opt/Espressif/ESP8266_NONOS_SDK/include/c_types.h" +#include "/opt/Espressif/ESP8266_NONOS_SDK/include/spi_flash.h" + int uart_rx_one_char(uint8_t *ch); uint8_t uart_rx_one_char_block(); int uart_tx_one_char(char ch); @@ -24,8 +27,13 @@ uint32_t SPIWrite(uint32_t addr, const uint32_t *src, uint32_t size); uint32_t SPIEraseChip(); uint32_t SPIEraseBlock(uint32_t block_num); uint32_t SPIEraseSector(uint32_t sector_num); -uint32_t SPI_read_status(); -uint32_t Wait_SPI_Idle(); + +extern SpiFlashChip *flashchip; +uint32_t Wait_SPI_Idle(SpiFlashChip *spi); +uint32_t SPI_chip_erase(SpiFlashChip *spi); +uint32_t SPI_read_status(SpiFlashChip *spi); +uint32_t SPI_write_enable(SpiFlashChip *spi); + void spi_flash_attach(); /* ESP32 API compatibility */ diff --git a/common/platforms/esp8266/stubs/stub.ld b/common/platforms/esp8266/stubs/stub.ld index 81b171c..f54a4f8 100644 --- a/common/platforms/esp8266/stubs/stub.ld +++ b/common/platforms/esp8266/stubs/stub.ld @@ -5,7 +5,7 @@ MEMORY { iram : org = 0x40100000, len = 0x8000 - dram : org = 0x3FFE8000, len = 0x18000 + dram : org = 0x3FFE8000, len = 0x14000 } ENTRY(stub_main) @@ -39,3 +39,5 @@ SECTIONS { INCLUDE "eagle.rom.addr.v6.ld" PROVIDE(SPIFlashModeConfig = 0x40004568); +PROVIDE(SPI_erase_sector = 0x400040c0); +PROVIDE(SPI_erase_block = 0x40004120); From c26764d6c9e04597f6edc6d97efe1b6ecf3d9d38 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 25 Jul 2017 13:42:48 +0200 Subject: [PATCH 063/265] Add support for floats to ffi PUBLISHED_FROM=574dbc608fde2f5e4f5549f49cae715cd53e9328 --- mjs.c | 546 ++++++++++++++++++++++++++++++------------ mjs/src/ffi/ffi.c | 512 +++++++++++++++++++++++++++------------ mjs/src/ffi/ffi.h | 3 + mjs/src/mjs_ffi.c | 30 +++ mjs/src/mjs_ffi.h | 1 + mjs/tests/unit_test.c | 139 +++++++++++ 6 files changed, 925 insertions(+), 306 deletions(-) diff --git a/mjs.c b/mjs.c index 3fbd086..54ba8fc 100644 --- a/mjs.c +++ b/mjs.c @@ -1898,6 +1898,7 @@ typedef intptr_t ffi_word_t; enum ffi_ctype { FFI_CTYPE_WORD, FFI_CTYPE_BOOL, + FFI_CTYPE_FLOAT, FFI_CTYPE_DOUBLE, }; @@ -1906,6 +1907,7 @@ struct ffi_arg { union { uint64_t i; double d; + float f; } v; }; @@ -1916,6 +1918,7 @@ void ffi_set_word(struct ffi_arg *arg, ffi_word_t v); void ffi_set_bool(struct ffi_arg *arg, bool v); void ffi_set_ptr(struct ffi_arg *arg, void *v); void ffi_set_double(struct ffi_arg *arg, double v); +void ffi_set_float(struct ffi_arg *arg, float v); #if defined(__cplusplus) } @@ -2421,6 +2424,7 @@ enum mjs_ffi_ctype { MJS_FFI_CTYPE_INT, MJS_FFI_CTYPE_BOOL, MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, MJS_FFI_CTYPE_CHAR_PTR, MJS_FFI_CTYPE_VOID_PTR, MJS_FFI_CTYPE_INVALID, @@ -6037,9 +6041,11 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { #define IS_W(arg) ((arg).ctype == FFI_CTYPE_WORD) #define IS_D(arg) ((arg).ctype == FFI_CTYPE_DOUBLE) +#define IS_F(arg) ((arg).ctype == FFI_CTYPE_FLOAT) #define W(arg) ((ffi_word_t)(arg).v.i) #define D(arg) ((arg).v.d) +#define F(arg) ((arg).v.f) void ffi_set_word(struct ffi_arg *arg, ffi_word_t v) { arg->ctype = FFI_CTYPE_WORD; @@ -6060,6 +6066,11 @@ void ffi_set_double(struct ffi_arg *arg, double v) { arg->v.d = v; } +void ffi_set_float(struct ffi_arg *arg, float v) { + arg->ctype = FFI_CTYPE_FLOAT; + arg->v.f = v; +} + /* * The ARM ABI uses only 4 32-bit registers for paramter passing. * Xtensa call0 calling-convention (as used by Espressif) has 6. @@ -6113,6 +6124,18 @@ typedef ffi_word_t (*wdwd_t)(double, ffi_word_t, double); typedef ffi_word_t (*wddw_t)(double, double, ffi_word_t); typedef ffi_word_t (*wddd_t)(double, double, double); +typedef ffi_word_t (*wfw_t)(float, ffi_word_t); +typedef ffi_word_t (*wwf_t)(ffi_word_t, float); +typedef ffi_word_t (*wff_t)(float, float); + +typedef ffi_word_t (*wwwf_t)(ffi_word_t, ffi_word_t, float); +typedef ffi_word_t (*wwfw_t)(ffi_word_t, float, ffi_word_t); +typedef ffi_word_t (*wwff_t)(ffi_word_t, float, float); +typedef ffi_word_t (*wfww_t)(float, ffi_word_t, ffi_word_t); +typedef ffi_word_t (*wfwf_t)(float, ffi_word_t, float); +typedef ffi_word_t (*wffw_t)(float, float, ffi_word_t); +typedef ffi_word_t (*wfff_t)(float, float, float); + typedef bool (*b4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef bool (*b5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -6130,6 +6153,18 @@ typedef bool (*bdwd_t)(double, ffi_word_t, double); typedef bool (*bddw_t)(double, double, ffi_word_t); typedef bool (*bddd_t)(double, double, double); +typedef bool (*bfw_t)(float, ffi_word_t); +typedef bool (*bwf_t)(ffi_word_t, float); +typedef bool (*bff_t)(float, float); + +typedef bool (*bwwf_t)(ffi_word_t, ffi_word_t, float); +typedef bool (*bwfw_t)(ffi_word_t, float, ffi_word_t); +typedef bool (*bwff_t)(ffi_word_t, float, float); +typedef bool (*bfww_t)(float, ffi_word_t, ffi_word_t); +typedef bool (*bfwf_t)(float, ffi_word_t, float); +typedef bool (*bffw_t)(float, float, ffi_word_t); +typedef bool (*bfff_t)(float, float, float); + typedef double (*d4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef double (*d5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -6147,21 +6182,46 @@ typedef double (*ddwd_t)(double, ffi_word_t, double); typedef double (*dddw_t)(double, double, ffi_word_t); typedef double (*dddd_t)(double, double, double); +typedef float (*f4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); +typedef float (*f5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, + ffi_word_t); +typedef float (*f6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, + ffi_word_t, ffi_word_t); +typedef float (*ffw_t)(float, ffi_word_t); +typedef float (*fwf_t)(ffi_word_t, float); +typedef float (*fff_t)(float, float); + +typedef float (*fwwf_t)(ffi_word_t, ffi_word_t, float); +typedef float (*fwfw_t)(ffi_word_t, float, ffi_word_t); +typedef float (*fwff_t)(ffi_word_t, float, float); +typedef float (*ffww_t)(float, ffi_word_t, ffi_word_t); +typedef float (*ffwf_t)(float, ffi_word_t, float); +typedef float (*fffw_t)(float, float, ffi_word_t); +typedef float (*ffff_t)(float, float, float); + int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, struct ffi_arg *args) { - int i, doubles = 0; + int i, doubles = 0, floats = 0; if (nargs > 6) return -1; for (i = 0; i < nargs; i++) { doubles += (IS_D(args[i])); + floats += (IS_F(args[i])); + } + + /* Doubles and floats are not supported together atm */ + if (doubles > 0 && floats > 0) { + return -1; } switch (res->ctype) { - case FFI_CTYPE_WORD: { + case FFI_CTYPE_WORD: { /* {{{ */ ffi_word_t r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments + if (doubles == 0) { + if (floats == 0) { + /* + * No double and no float args: we currently support up to 6 + * word-sized arguments */ if (nargs <= 4) { w4w_t f = (w4w_t) func; @@ -6176,44 +6236,46 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, } else { abort(); } - break; - } - case 1: + } else { + /* There are some floats */ switch (nargs) { case 0: case 1: case 2: - if (IS_D(args[0])) { - wdw_t f = (wdw_t) func; - r = f(D(args[0]), W(args[1])); + if (IS_F(args[0]) && IS_F(args[1])) { + wff_t f = (wff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + wfw_t f = (wfw_t) func; + r = f(F(args[0]), W(args[1])); } else { - wwd_t f = (wwd_t) func; - r = f(W(args[0]), D(args[1])); + wwf_t f = (wwf_t) func; + r = f(W(args[0]), F(args[1])); } break; case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - wwwd_t f = (wwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - wwdw_t f = (wwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - wwdd_t f = (wwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - wdww_t f = (wdww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - wdwd_t f = (wdwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - wddw_t f = (wddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - wddd_t f = (wddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + wwwf_t f = (wwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + wwfw_t f = (wwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + wwff_t f = (wwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wfww_t f = (wfww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + wfwf_t f = (wfwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + wffw_t f = (wffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + wfff_t f = (wfff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); } else { // The above checks should be exhaustive abort(); @@ -6222,21 +6284,65 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } - break; - case 2: { - wdd_t f = (wdd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; + } + } else { + /* There are some doubles */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + wdd_t f = (wdd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + wdw_t f = (wdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + wwd_t f = (wwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wwwd_t f = (wwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wwdw_t f = (wwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wwdd_t f = (wwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wdww_t f = (wdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wdwd_t f = (wdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wddw_t f = (wddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wddd_t f = (wddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } } res->v.i = (uint64_t) r; - } break; - case FFI_CTYPE_BOOL: { + } break; /* }}} */ + case FFI_CTYPE_BOOL: { /* {{{ */ ffi_word_t r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments + if (doubles == 0) { + if (floats == 0) { + /* + * No double and no float args: we currently support up to 6 + * word-sized arguments */ if (nargs <= 4) { b4w_t f = (b4w_t) func; @@ -6251,44 +6357,46 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, } else { abort(); } - break; - } - case 1: { + } else { + /* There are some floats */ switch (nargs) { case 0: case 1: case 2: - if (IS_D(args[0])) { - bdw_t f = (bdw_t) func; - r = f(D(args[0]), W(args[1])); + if (IS_F(args[0]) && IS_F(args[1])) { + bff_t f = (bff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + bfw_t f = (bfw_t) func; + r = f(F(args[0]), W(args[1])); } else { - bwd_t f = (bwd_t) func; - r = f(W(args[0]), D(args[1])); + bwf_t f = (bwf_t) func; + r = f(W(args[0]), F(args[1])); } break; case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - bwwd_t f = (bwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - bwdw_t f = (bwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - bwdd_t f = (bwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - bdww_t f = (bdww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - bdwd_t f = (bdwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - bddw_t f = (bddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - bddd_t f = (bddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + bwwf_t f = (bwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + bwfw_t f = (bwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + bwff_t f = (bwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bfww_t f = (bfww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + bfwf_t f = (bfwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + bffw_t f = (bffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + bfff_t f = (bfff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); } else { // The above checks should be exhaustive abort(); @@ -6297,93 +6405,195 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } - break; } - case 2: { - bdd_t f = (bdd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; + } else { + /* There are some doubles */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + bdd_t f = (bdd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + bdw_t f = (bdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + bwd_t f = (bwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bwwd_t f = (bwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bwdw_t f = (bwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bwdd_t f = (bwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bdww_t f = (bdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bdwd_t f = (bdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bddw_t f = (bddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bddd_t f = (bddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } } res->v.i = (uint64_t) r; - } break; - case FFI_CTYPE_DOUBLE: { + } break; /* }}} */ + case FFI_CTYPE_DOUBLE: { /* {{{ */ double r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments - */ - if (nargs <= 4) { - d4w_t f = (d4w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); - } else if (nargs == 5) { - d5w_t f = (d5w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); - } else if (nargs == 6) { - d6w_t f = (d6w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), - W(args[5])); - } else { - abort(); - } - break; + if (doubles == 0) { + /* No double args: we currently support up to 6 word-sized arguments + */ + if (nargs <= 4) { + d4w_t f = (d4w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); + } else if (nargs == 5) { + d5w_t f = (d5w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); + } else if (nargs == 6) { + d6w_t f = (d6w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); + } else { + abort(); } - case 1: { - switch (nargs) { - case 0: - case 1: - case 2: - if (IS_D(args[0])) { - ddw_t f = (ddw_t) func; - r = f(D(args[0]), W(args[1])); - } else { - dwd_t f = (dwd_t) func; - r = f(W(args[0]), D(args[1])); - } - break; + } else { + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + ddd_t f = (ddd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + ddw_t f = (ddw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + dwd_t f = (dwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; - case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - dwwd_t f = (dwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - dwdw_t f = (dwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - dwdd_t f = (dwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - ddww_t f = (ddww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - ddwd_t f = (ddwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - dddw_t f = (dddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - dddd_t f = (dddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); - } else { - // The above checks should be exhaustive - abort(); - } - break; - default: - return -1; - } - break; + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + dwwd_t f = (dwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dwdw_t f = (dwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dwdd_t f = (dwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ddww_t f = (ddww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + ddwd_t f = (ddwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dddw_t f = (dddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dddd_t f = (dddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } - case 2: { - ddd_t f = (ddd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; } res->v.d = r; - } break; + } break; /* }}} */ + case FFI_CTYPE_FLOAT: { /* {{{ */ + double r; + if (floats == 0) { + /* No float args: we currently support up to 6 word-sized arguments + */ + if (nargs <= 4) { + f4w_t f = (f4w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); + } else if (nargs == 5) { + f5w_t f = (f5w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); + } else if (nargs == 6) { + f6w_t f = (f6w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); + } else { + abort(); + } + } else { + /* There are some float args */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_F(args[0]) && IS_F(args[1])) { + fff_t f = (fff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + ffw_t f = (ffw_t) func; + r = f(F(args[0]), W(args[1])); + } else { + fwf_t f = (fwf_t) func; + r = f(W(args[0]), F(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + fwwf_t f = (fwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + fwfw_t f = (fwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + fwff_t f = (fwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ffww_t f = (ffww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + ffwf_t f = (ffwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + fffw_t f = (fffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + ffff_t f = (ffff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } + } + res->v.f = r; + } break; /* }}} */ } return 0; @@ -8598,6 +8808,8 @@ static mjs_ffi_ctype_t parse_cval_type(struct mjs *mjs, const char *s, return MJS_FFI_CTYPE_BOOL; } else if (strncmp(s, "double", e - s) == 0) { return MJS_FFI_CTYPE_DOUBLE; + } else if (strncmp(s, "float", e - s) == 0) { + return MJS_FFI_CTYPE_FLOAT; } else if (strncmp(s, "char*", 5) == 0 || strncmp(s, "char *", 6) == 0) { return MJS_FFI_CTYPE_CHAR_PTR; } else if (strncmp(s, "void*", 5) == 0 || strncmp(s, "void *", 6) == 0) { @@ -8799,6 +9011,7 @@ union ffi_cb_data_val { void *p; uintptr_t w; double d; + float f; }; struct ffi_cb_data { @@ -8847,6 +9060,9 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_DOUBLE: args[i] = mjs_mk_number(mjs, data->args[i].d); break; + case MJS_FFI_CTYPE_FLOAT: + args[i] = mjs_mk_number(mjs, data->args[i].f); + break; default: /* should never be here */ LOG(LL_ERROR, ("unexpected val type for arg #%d: %d\n", i, val_type)); @@ -8898,6 +9114,9 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_DOUBLE: ret.d = mjs_get_double(mjs, res); break; + case MJS_FFI_CTYPE_FLOAT: + ret.f = (float) mjs_get_double(mjs, res); + break; default: /* should never be here */ LOG(LL_ERROR, ("unexpected return val type %d\n", return_ctype)); @@ -9000,6 +9219,7 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { if (sig->is_valid) { int i; int double_cnt = 0; + int float_cnt = 0; int userdata_idx = 0 /* not a valid value: index 0 means return value */; for (i = 1 /*0th item is a return value*/; i < MJS_CB_SIGNATURE_MAX_SIZE; @@ -9009,6 +9229,9 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { case MJS_FFI_CTYPE_DOUBLE: double_cnt++; break; + case MJS_FFI_CTYPE_FLOAT: + float_cnt++; + break; case MJS_FFI_CTYPE_USERDATA: assert(userdata_idx == 0); /* Otherwise is_valid should be 0 */ userdata_idx = i; @@ -9018,6 +9241,11 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { } } + if (float_cnt > 0) { + /* TODO(dfrank): add support for floats in callbacks */ + return NULL; + } + assert(userdata_idx > 0); /* Otherwise is_valid should be 0 */ if (sig->args_cnt <= MJS_CB_ARGS_MAX_CNT) { @@ -9157,6 +9385,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: res.ctype = FFI_CTYPE_DOUBLE; break; + case MJS_FFI_CTYPE_FLOAT: + res.ctype = FFI_CTYPE_FLOAT; + break; case MJS_FFI_CTYPE_BOOL: res.ctype = FFI_CTYPE_BOOL; break; @@ -9251,6 +9482,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: ffi_set_double(&args[i], mjs_get_double(mjs, arg)); break; + case MJS_FFI_CTYPE_FLOAT: + ffi_set_float(&args[i], (float) mjs_get_double(mjs, arg)); + break; case MJS_FFI_CTYPE_CHAR_PTR: { size_t s; if (!mjs_is_string(arg)) { @@ -9367,6 +9601,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: resv = mjs_mk_number(mjs, res.v.d); break; + case MJS_FFI_CTYPE_FLOAT: + resv = mjs_mk_number(mjs, res.v.f); + break; default: resv = mjs_mk_undefined(); break; @@ -9470,6 +9707,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, sig->val_types[0] != MJS_FFI_CTYPE_INT && sig->val_types[0] != MJS_FFI_CTYPE_BOOL && sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE && + sig->val_types[0] != MJS_FFI_CTYPE_FLOAT && sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR && sig->val_types[0] != MJS_FFI_CTYPE_CHAR_PTR) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "wrong return value type"); @@ -9482,6 +9720,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, sig->val_types[0] != MJS_FFI_CTYPE_INT && sig->val_types[0] != MJS_FFI_CTYPE_BOOL && sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE && + sig->val_types[0] != MJS_FFI_CTYPE_FLOAT && sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "wrong return value type"); goto clean; @@ -9518,6 +9757,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, case MJS_FFI_CTYPE_VOID_PTR: case MJS_FFI_CTYPE_CHAR_PTR: case MJS_FFI_CTYPE_DOUBLE: + case MJS_FFI_CTYPE_FLOAT: /* Do nothing */ break; case MJS_FFI_CTYPE_NONE: diff --git a/mjs/src/ffi/ffi.c b/mjs/src/ffi/ffi.c index c9ebabc..05535dc 100644 --- a/mjs/src/ffi/ffi.c +++ b/mjs/src/ffi/ffi.c @@ -7,9 +7,11 @@ #define IS_W(arg) ((arg).ctype == FFI_CTYPE_WORD) #define IS_D(arg) ((arg).ctype == FFI_CTYPE_DOUBLE) +#define IS_F(arg) ((arg).ctype == FFI_CTYPE_FLOAT) #define W(arg) ((ffi_word_t)(arg).v.i) #define D(arg) ((arg).v.d) +#define F(arg) ((arg).v.f) void ffi_set_word(struct ffi_arg *arg, ffi_word_t v) { arg->ctype = FFI_CTYPE_WORD; @@ -30,6 +32,11 @@ void ffi_set_double(struct ffi_arg *arg, double v) { arg->v.d = v; } +void ffi_set_float(struct ffi_arg *arg, float v) { + arg->ctype = FFI_CTYPE_FLOAT; + arg->v.f = v; +} + /* * The ARM ABI uses only 4 32-bit registers for paramter passing. * Xtensa call0 calling-convention (as used by Espressif) has 6. @@ -83,6 +90,18 @@ typedef ffi_word_t (*wdwd_t)(double, ffi_word_t, double); typedef ffi_word_t (*wddw_t)(double, double, ffi_word_t); typedef ffi_word_t (*wddd_t)(double, double, double); +typedef ffi_word_t (*wfw_t)(float, ffi_word_t); +typedef ffi_word_t (*wwf_t)(ffi_word_t, float); +typedef ffi_word_t (*wff_t)(float, float); + +typedef ffi_word_t (*wwwf_t)(ffi_word_t, ffi_word_t, float); +typedef ffi_word_t (*wwfw_t)(ffi_word_t, float, ffi_word_t); +typedef ffi_word_t (*wwff_t)(ffi_word_t, float, float); +typedef ffi_word_t (*wfww_t)(float, ffi_word_t, ffi_word_t); +typedef ffi_word_t (*wfwf_t)(float, ffi_word_t, float); +typedef ffi_word_t (*wffw_t)(float, float, ffi_word_t); +typedef ffi_word_t (*wfff_t)(float, float, float); + typedef bool (*b4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef bool (*b5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -100,6 +119,18 @@ typedef bool (*bdwd_t)(double, ffi_word_t, double); typedef bool (*bddw_t)(double, double, ffi_word_t); typedef bool (*bddd_t)(double, double, double); +typedef bool (*bfw_t)(float, ffi_word_t); +typedef bool (*bwf_t)(ffi_word_t, float); +typedef bool (*bff_t)(float, float); + +typedef bool (*bwwf_t)(ffi_word_t, ffi_word_t, float); +typedef bool (*bwfw_t)(ffi_word_t, float, ffi_word_t); +typedef bool (*bwff_t)(ffi_word_t, float, float); +typedef bool (*bfww_t)(float, ffi_word_t, ffi_word_t); +typedef bool (*bfwf_t)(float, ffi_word_t, float); +typedef bool (*bffw_t)(float, float, ffi_word_t); +typedef bool (*bfff_t)(float, float, float); + typedef double (*d4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); typedef double (*d5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); @@ -117,21 +148,46 @@ typedef double (*ddwd_t)(double, ffi_word_t, double); typedef double (*dddw_t)(double, double, ffi_word_t); typedef double (*dddd_t)(double, double, double); +typedef float (*f4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t); +typedef float (*f5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, + ffi_word_t); +typedef float (*f6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t, + ffi_word_t, ffi_word_t); +typedef float (*ffw_t)(float, ffi_word_t); +typedef float (*fwf_t)(ffi_word_t, float); +typedef float (*fff_t)(float, float); + +typedef float (*fwwf_t)(ffi_word_t, ffi_word_t, float); +typedef float (*fwfw_t)(ffi_word_t, float, ffi_word_t); +typedef float (*fwff_t)(ffi_word_t, float, float); +typedef float (*ffww_t)(float, ffi_word_t, ffi_word_t); +typedef float (*ffwf_t)(float, ffi_word_t, float); +typedef float (*fffw_t)(float, float, ffi_word_t); +typedef float (*ffff_t)(float, float, float); + int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, struct ffi_arg *args) { - int i, doubles = 0; + int i, doubles = 0, floats = 0; if (nargs > 6) return -1; for (i = 0; i < nargs; i++) { doubles += (IS_D(args[i])); + floats += (IS_F(args[i])); + } + + /* Doubles and floats are not supported together atm */ + if (doubles > 0 && floats > 0) { + return -1; } switch (res->ctype) { - case FFI_CTYPE_WORD: { + case FFI_CTYPE_WORD: { /* {{{ */ ffi_word_t r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments + if (doubles == 0) { + if (floats == 0) { + /* + * No double and no float args: we currently support up to 6 + * word-sized arguments */ if (nargs <= 4) { w4w_t f = (w4w_t) func; @@ -146,44 +202,46 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, } else { abort(); } - break; - } - case 1: + } else { + /* There are some floats */ switch (nargs) { case 0: case 1: case 2: - if (IS_D(args[0])) { - wdw_t f = (wdw_t) func; - r = f(D(args[0]), W(args[1])); + if (IS_F(args[0]) && IS_F(args[1])) { + wff_t f = (wff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + wfw_t f = (wfw_t) func; + r = f(F(args[0]), W(args[1])); } else { - wwd_t f = (wwd_t) func; - r = f(W(args[0]), D(args[1])); + wwf_t f = (wwf_t) func; + r = f(W(args[0]), F(args[1])); } break; case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - wwwd_t f = (wwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - wwdw_t f = (wwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - wwdd_t f = (wwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - wdww_t f = (wdww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - wdwd_t f = (wdwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - wddw_t f = (wddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - wddd_t f = (wddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + wwwf_t f = (wwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + wwfw_t f = (wwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + wwff_t f = (wwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wfww_t f = (wfww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + wfwf_t f = (wfwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + wffw_t f = (wffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + wfff_t f = (wfff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); } else { // The above checks should be exhaustive abort(); @@ -192,21 +250,65 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } - break; - case 2: { - wdd_t f = (wdd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; + } + } else { + /* There are some doubles */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + wdd_t f = (wdd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + wdw_t f = (wdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + wwd_t f = (wwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wwwd_t f = (wwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wwdw_t f = (wwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wwdd_t f = (wwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + wdww_t f = (wdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + wdwd_t f = (wdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + wddw_t f = (wddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + wddd_t f = (wddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } } res->v.i = (uint64_t) r; - } break; - case FFI_CTYPE_BOOL: { + } break; /* }}} */ + case FFI_CTYPE_BOOL: { /* {{{ */ ffi_word_t r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments + if (doubles == 0) { + if (floats == 0) { + /* + * No double and no float args: we currently support up to 6 + * word-sized arguments */ if (nargs <= 4) { b4w_t f = (b4w_t) func; @@ -221,44 +323,46 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, } else { abort(); } - break; - } - case 1: { + } else { + /* There are some floats */ switch (nargs) { case 0: case 1: case 2: - if (IS_D(args[0])) { - bdw_t f = (bdw_t) func; - r = f(D(args[0]), W(args[1])); + if (IS_F(args[0]) && IS_F(args[1])) { + bff_t f = (bff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + bfw_t f = (bfw_t) func; + r = f(F(args[0]), W(args[1])); } else { - bwd_t f = (bwd_t) func; - r = f(W(args[0]), D(args[1])); + bwf_t f = (bwf_t) func; + r = f(W(args[0]), F(args[1])); } break; case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - bwwd_t f = (bwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - bwdw_t f = (bwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - bwdd_t f = (bwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - bdww_t f = (bdww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - bdwd_t f = (bdwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - bddw_t f = (bddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - bddd_t f = (bddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + bwwf_t f = (bwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + bwfw_t f = (bwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + bwff_t f = (bwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bfww_t f = (bfww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + bfwf_t f = (bfwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + bffw_t f = (bffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + bfff_t f = (bfff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); } else { // The above checks should be exhaustive abort(); @@ -267,93 +371,195 @@ int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res, default: return -1; } - break; } - case 2: { - bdd_t f = (bdd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; + } else { + /* There are some doubles */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + bdd_t f = (bdd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + bdw_t f = (bdw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + bwd_t f = (bwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bwwd_t f = (bwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bwdw_t f = (bwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bwdd_t f = (bwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + bdww_t f = (bdww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + bdwd_t f = (bdwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + bddw_t f = (bddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + bddd_t f = (bddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } } res->v.i = (uint64_t) r; - } break; - case FFI_CTYPE_DOUBLE: { + } break; /* }}} */ + case FFI_CTYPE_DOUBLE: { /* {{{ */ double r; - switch (doubles) { - case 0: { - /* No double args: we currently support up to 6 word-sized arguments - */ - if (nargs <= 4) { - d4w_t f = (d4w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); - } else if (nargs == 5) { - d5w_t f = (d5w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); - } else if (nargs == 6) { - d6w_t f = (d6w_t) func; - r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), - W(args[5])); - } else { - abort(); - } - break; + if (doubles == 0) { + /* No double args: we currently support up to 6 word-sized arguments + */ + if (nargs <= 4) { + d4w_t f = (d4w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); + } else if (nargs == 5) { + d5w_t f = (d5w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); + } else if (nargs == 6) { + d6w_t f = (d6w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); + } else { + abort(); } - case 1: { - switch (nargs) { - case 0: - case 1: - case 2: - if (IS_D(args[0])) { - ddw_t f = (ddw_t) func; - r = f(D(args[0]), W(args[1])); - } else { - dwd_t f = (dwd_t) func; - r = f(W(args[0]), D(args[1])); - } - break; + } else { + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_D(args[0]) && IS_D(args[1])) { + ddd_t f = (ddd_t) func; + r = f(D(args[0]), D(args[1])); + } else if (IS_D(args[0])) { + ddw_t f = (ddw_t) func; + r = f(D(args[0]), W(args[1])); + } else { + dwd_t f = (dwd_t) func; + r = f(W(args[0]), D(args[1])); + } + break; - case 3: - if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - dwwd_t f = (dwwd_t) func; - r = f(W(args[0]), W(args[1]), D(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - dwdw_t f = (dwdw_t) func; - r = f(W(args[0]), D(args[1]), W(args[2])); - } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - dwdd_t f = (dwdd_t) func; - r = f(W(args[0]), D(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { - ddww_t f = (ddww_t) func; - r = f(D(args[0]), W(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { - ddwd_t f = (ddwd_t) func; - r = f(D(args[0]), W(args[1]), D(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { - dddw_t f = (dddw_t) func; - r = f(D(args[0]), D(args[1]), W(args[2])); - } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { - dddd_t f = (dddd_t) func; - r = f(D(args[0]), D(args[1]), D(args[2])); - } else { - // The above checks should be exhaustive - abort(); - } - break; - default: - return -1; - } - break; + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + dwwd_t f = (dwwd_t) func; + r = f(W(args[0]), W(args[1]), D(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dwdw_t f = (dwdw_t) func; + r = f(W(args[0]), D(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dwdd_t f = (dwdd_t) func; + r = f(W(args[0]), D(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ddww_t f = (ddww_t) func; + r = f(D(args[0]), W(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) { + ddwd_t f = (ddwd_t) func; + r = f(D(args[0]), W(args[1]), D(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) { + dddw_t f = (dddw_t) func; + r = f(D(args[0]), D(args[1]), W(args[2])); + } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) { + dddd_t f = (dddd_t) func; + r = f(D(args[0]), D(args[1]), D(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; } - case 2: { - ddd_t f = (ddd_t) func; - r = f(D(args[0]), D(args[1])); - } break; - default: - return -1; } res->v.d = r; - } break; + } break; /* }}} */ + case FFI_CTYPE_FLOAT: { /* {{{ */ + double r; + if (floats == 0) { + /* No float args: we currently support up to 6 word-sized arguments + */ + if (nargs <= 4) { + f4w_t f = (f4w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3])); + } else if (nargs == 5) { + f5w_t f = (f5w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4])); + } else if (nargs == 6) { + f6w_t f = (f6w_t) func; + r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]), + W(args[5])); + } else { + abort(); + } + } else { + /* There are some float args */ + switch (nargs) { + case 0: + case 1: + case 2: + if (IS_F(args[0]) && IS_F(args[1])) { + fff_t f = (fff_t) func; + r = f(F(args[0]), F(args[1])); + } else if (IS_F(args[0])) { + ffw_t f = (ffw_t) func; + r = f(F(args[0]), W(args[1])); + } else { + fwf_t f = (fwf_t) func; + r = f(W(args[0]), F(args[1])); + } + break; + + case 3: + if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + fwwf_t f = (fwwf_t) func; + r = f(W(args[0]), W(args[1]), F(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + fwfw_t f = (fwfw_t) func; + r = f(W(args[0]), F(args[1]), W(args[2])); + } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + fwff_t f = (fwff_t) func; + r = f(W(args[0]), F(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) { + ffww_t f = (ffww_t) func; + r = f(F(args[0]), W(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) { + ffwf_t f = (ffwf_t) func; + r = f(F(args[0]), W(args[1]), F(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) { + fffw_t f = (fffw_t) func; + r = f(F(args[0]), F(args[1]), W(args[2])); + } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) { + ffff_t f = (ffff_t) func; + r = f(F(args[0]), F(args[1]), F(args[2])); + } else { + // The above checks should be exhaustive + abort(); + } + break; + default: + return -1; + } + } + res->v.f = r; + } break; /* }}} */ } return 0; diff --git a/mjs/src/ffi/ffi.h b/mjs/src/ffi/ffi.h index d51102e..7e46210 100644 --- a/mjs/src/ffi/ffi.h +++ b/mjs/src/ffi/ffi.h @@ -26,6 +26,7 @@ typedef intptr_t ffi_word_t; enum ffi_ctype { FFI_CTYPE_WORD, FFI_CTYPE_BOOL, + FFI_CTYPE_FLOAT, FFI_CTYPE_DOUBLE, }; @@ -34,6 +35,7 @@ struct ffi_arg { union { uint64_t i; double d; + float f; } v; }; @@ -44,6 +46,7 @@ void ffi_set_word(struct ffi_arg *arg, ffi_word_t v); void ffi_set_bool(struct ffi_arg *arg, bool v); void ffi_set_ptr(struct ffi_arg *arg, void *v); void ffi_set_double(struct ffi_arg *arg, double v); +void ffi_set_float(struct ffi_arg *arg, float v); #if defined(__cplusplus) } diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index 457b721..c5dadd1 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -54,6 +54,8 @@ static mjs_ffi_ctype_t parse_cval_type(struct mjs *mjs, const char *s, return MJS_FFI_CTYPE_BOOL; } else if (strncmp(s, "double", e - s) == 0) { return MJS_FFI_CTYPE_DOUBLE; + } else if (strncmp(s, "float", e - s) == 0) { + return MJS_FFI_CTYPE_FLOAT; } else if (strncmp(s, "char*", 5) == 0 || strncmp(s, "char *", 6) == 0) { return MJS_FFI_CTYPE_CHAR_PTR; } else if (strncmp(s, "void*", 5) == 0 || strncmp(s, "void *", 6) == 0) { @@ -255,6 +257,7 @@ union ffi_cb_data_val { void *p; uintptr_t w; double d; + float f; }; struct ffi_cb_data { @@ -303,6 +306,9 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_DOUBLE: args[i] = mjs_mk_number(mjs, data->args[i].d); break; + case MJS_FFI_CTYPE_FLOAT: + args[i] = mjs_mk_number(mjs, data->args[i].f); + break; default: /* should never be here */ LOG(LL_ERROR, ("unexpected val type for arg #%d: %d\n", i, val_type)); @@ -354,6 +360,9 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_DOUBLE: ret.d = mjs_get_double(mjs, res); break; + case MJS_FFI_CTYPE_FLOAT: + ret.f = (float) mjs_get_double(mjs, res); + break; default: /* should never be here */ LOG(LL_ERROR, ("unexpected return val type %d\n", return_ctype)); @@ -456,6 +465,7 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { if (sig->is_valid) { int i; int double_cnt = 0; + int float_cnt = 0; int userdata_idx = 0 /* not a valid value: index 0 means return value */; for (i = 1 /*0th item is a return value*/; i < MJS_CB_SIGNATURE_MAX_SIZE; @@ -465,6 +475,9 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { case MJS_FFI_CTYPE_DOUBLE: double_cnt++; break; + case MJS_FFI_CTYPE_FLOAT: + float_cnt++; + break; case MJS_FFI_CTYPE_USERDATA: assert(userdata_idx == 0); /* Otherwise is_valid should be 0 */ userdata_idx = i; @@ -474,6 +487,11 @@ static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) { } } + if (float_cnt > 0) { + /* TODO(dfrank): add support for floats in callbacks */ + return NULL; + } + assert(userdata_idx > 0); /* Otherwise is_valid should be 0 */ if (sig->args_cnt <= MJS_CB_ARGS_MAX_CNT) { @@ -613,6 +631,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: res.ctype = FFI_CTYPE_DOUBLE; break; + case MJS_FFI_CTYPE_FLOAT: + res.ctype = FFI_CTYPE_FLOAT; + break; case MJS_FFI_CTYPE_BOOL: res.ctype = FFI_CTYPE_BOOL; break; @@ -707,6 +728,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: ffi_set_double(&args[i], mjs_get_double(mjs, arg)); break; + case MJS_FFI_CTYPE_FLOAT: + ffi_set_float(&args[i], (float) mjs_get_double(mjs, arg)); + break; case MJS_FFI_CTYPE_CHAR_PTR: { size_t s; if (!mjs_is_string(arg)) { @@ -823,6 +847,9 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { case MJS_FFI_CTYPE_DOUBLE: resv = mjs_mk_number(mjs, res.v.d); break; + case MJS_FFI_CTYPE_FLOAT: + resv = mjs_mk_number(mjs, res.v.f); + break; default: resv = mjs_mk_undefined(); break; @@ -926,6 +953,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, sig->val_types[0] != MJS_FFI_CTYPE_INT && sig->val_types[0] != MJS_FFI_CTYPE_BOOL && sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE && + sig->val_types[0] != MJS_FFI_CTYPE_FLOAT && sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR && sig->val_types[0] != MJS_FFI_CTYPE_CHAR_PTR) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "wrong return value type"); @@ -938,6 +966,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, sig->val_types[0] != MJS_FFI_CTYPE_INT && sig->val_types[0] != MJS_FFI_CTYPE_BOOL && sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE && + sig->val_types[0] != MJS_FFI_CTYPE_FLOAT && sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "wrong return value type"); goto clean; @@ -974,6 +1003,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, case MJS_FFI_CTYPE_VOID_PTR: case MJS_FFI_CTYPE_CHAR_PTR: case MJS_FFI_CTYPE_DOUBLE: + case MJS_FFI_CTYPE_FLOAT: /* Do nothing */ break; case MJS_FFI_CTYPE_NONE: diff --git a/mjs/src/mjs_ffi.h b/mjs/src/mjs_ffi.h index a83118c..dc08539 100644 --- a/mjs/src/mjs_ffi.h +++ b/mjs/src/mjs_ffi.h @@ -26,6 +26,7 @@ enum mjs_ffi_ctype { MJS_FFI_CTYPE_INT, MJS_FFI_CTYPE_BOOL, MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, MJS_FFI_CTYPE_CHAR_PTR, MJS_FFI_CTYPE_VOID_PTR, MJS_FFI_CTYPE_INVALID, diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index dca229e..1a48c63 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -636,6 +636,7 @@ int ffi_test_i2i(int a0, int a1) { return a0 - a1; } +/* 3 arg, one double {{{ */ int ffi_test_iiid(int a0, int a1, double d2) { return (d2 * a0 - a1) * 1000; } @@ -649,6 +650,55 @@ bool ffi_test_biid(int a0, int a1, double d2) { double ffi_test_diid(int a0, int a1, double d2) { return d2 * a0 - a1; } +/* }}} */ + +/* 3 arg, two doubles {{{ */ +int ffi_test_iidd(int a0, double a1, double d2) { + return (d2 * a0 - a1) * 1000; +} + +bool ffi_test_bidd(int a0, double a1, double d2) { + (void) a0; + (void) a1; + return d2 > 10.0; +} + +double ffi_test_didd(int a0, double a1, double d2) { + return d2 * a0 - a1; +} +/* }}} */ + +/* 3 arg, one float {{{ */ +int ffi_test_iiif(int a0, int a1, float f2) { + return (f2 * a0 - a1) * 1000; +} + +bool ffi_test_biif(int a0, int a1, float f2) { + (void) a0; + (void) a1; + return f2 > 10.0; +} + +float ffi_test_fiif(int a0, int a1, float f2) { + return f2 * a0 - a1; +} +/* }}} */ + +/* 3 arg, two floats {{{ */ +int ffi_test_iiff(int a0, float a1, float f2) { + return (f2 * a0 - a1) * 1000; +} + +bool ffi_test_biff(int a0, float a1, float f2) { + (void) a0; + (void) a1; + return f2 > 10.0; +} + +float ffi_test_fiff(int a0, float a1, float f2) { + return f2 * a0 - a1; +} +/* }}} */ int ffi_test_iib(int a0, bool b) { return a0 - (b ? 10 : 20); @@ -770,6 +820,15 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "ffi_test_iiid") == 0) return ffi_test_iiid; if (strcmp(name, "ffi_test_biid") == 0) return ffi_test_biid; if (strcmp(name, "ffi_test_diid") == 0) return ffi_test_diid; + if (strcmp(name, "ffi_test_iidd") == 0) return ffi_test_iidd; + if (strcmp(name, "ffi_test_bidd") == 0) return ffi_test_bidd; + if (strcmp(name, "ffi_test_didd") == 0) return ffi_test_didd; + if (strcmp(name, "ffi_test_iiif") == 0) return ffi_test_iiif; + if (strcmp(name, "ffi_test_biif") == 0) return ffi_test_biif; + if (strcmp(name, "ffi_test_fiif") == 0) return ffi_test_fiif; + if (strcmp(name, "ffi_test_iiff") == 0) return ffi_test_iiff; + if (strcmp(name, "ffi_test_biff") == 0) return ffi_test_biff; + if (strcmp(name, "ffi_test_fiff") == 0) return ffi_test_fiff; if (strcmp(name, "ffi_test_iib") == 0) return ffi_test_iib; if (strcmp(name, "ffi_test_bi") == 0) return ffi_test_bi; if (strcmp(name, "ffi_test_i5i") == 0) return ffi_test_i5i; @@ -1073,6 +1132,7 @@ const char *test_call_ffi(struct mjs *mjs) { /* ASSERT_STREQ(p, "ab"); */ } + /* 3 arg, one double {{{ */ ASSERT_EXEC_OK( mjs_exec(mjs, "let ffi_test_iiid = ffi('int ffi_test_iiid(int, int, double)')", &res)); @@ -1096,6 +1156,85 @@ const char *test_call_ffi(struct mjs *mjs) { ASSERT_EQ(mjs_exec(mjs, "ffi_test_biid(0, 0, 10.1)", &res), MJS_OK); ASSERT_EQ(mjs_get_bool(mjs, res), 1); + /* }}} */ + + /* 3 arg, two doubles {{{ */ + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_iidd = ffi('int ffi_test_iidd(int, double, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_iidd(3, 2.1, 13.4)", &res), MJS_OK); + ASSERT_EQ(mjs_get_int(mjs, res), 38100); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_didd = ffi('double ffi_test_didd(int, double, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_didd(3, 2.1, 13.4)", &res), MJS_OK); + ASSERT_EQ(mjs_get_double(mjs, res), 38.1); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_bidd = ffi('bool ffi_test_bidd(int, double, double)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_bidd(0, 0, 10)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_bidd(0, 0, 10.1)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + /* }}} */ + + /* 3 arg, one float {{{ */ + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_iiif = ffi('int ffi_test_iiif(int, int, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_iiif(3, 2, 13.5)", &res), MJS_OK); + ASSERT_EQ(mjs_get_int(mjs, res), 38500); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_fiif = ffi('float ffi_test_fiif(int, int, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_fiif(3, 2, 13.5)", &res), MJS_OK); + ASSERT_EQ(mjs_get_double(mjs, res), 38.5); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_biif = ffi('bool ffi_test_biif(int, int, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biif(0, 0, 10)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biif(0, 0, 10.1)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + /* }}} */ + + /* 3 arg, two floats {{{ */ + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_iiff = ffi('int ffi_test_iiff(int, float, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_iiff(3, 2.0, 13.5)", &res), MJS_OK); + ASSERT_EQ(mjs_get_int(mjs, res), 38500); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_fiff = ffi('float ffi_test_fiff(int, float, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_fiff(3, 2.0, 13.5)", &res), MJS_OK); + ASSERT_EQ(mjs_get_double(mjs, res), 38.5); + + ASSERT_EXEC_OK( + mjs_exec(mjs, "let ffi_test_biff = ffi('bool ffi_test_biff(int, float, float)')", + &res)); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biff(0, 0, 10)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EQ(mjs_exec(mjs, "ffi_test_biff(0, 0, 10.1)", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + /* }}} */ mjs_disown(mjs, &res); From 78a15c462df40abc74c1348639257e557a2e863d Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 25 Jul 2017 15:36:30 +0300 Subject: [PATCH 064/265] Add support for NaN PUBLISHED_FROM=fcfa584c15a06b17879274c5d222f21e4d99f4fc --- mjs.c | 24 ++++++++++++++++++++++- mjs/src/mjs_builtin.c | 6 ++++++ mjs/src/mjs_exec.c | 4 +++- mjs/src/mjs_primitive.c | 9 +++++++++ mjs/src/mjs_primitive.h | 5 +++++ mjs/tests/unit_test.c | 43 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index 54ba8fc..2d24a96 100644 --- a/mjs.c +++ b/mjs.c @@ -3188,6 +3188,11 @@ MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p); */ MJS_PRIVATE void *get_ptr(mjs_val_t v); +/* + * Implementation for JS isNaN() + */ +MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -7116,6 +7121,12 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { v = mjs_mk_object(mjs); mjs_set(mjs, v, "create", ~0, mjs_mk_foreign(mjs, mjs_op_create_object)); mjs_set(mjs, obj, "Object", ~0, v); + + /* + * Populate numeric stuff + */ + mjs_set(mjs, obj, "NaN", ~0, MJS_TAG_NAN); + mjs_set(mjs, obj, "isNaN", ~0, mjs_mk_foreign(mjs, mjs_op_isnan)); } #ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_conversion.c" @@ -7853,7 +7864,9 @@ static void op_assign(struct mjs *mjs, int op) { static int check_equal(struct mjs *mjs, mjs_val_t a, mjs_val_t b) { int ret = 0; - if (a == b) { + if (a == MJS_TAG_NAN && b == MJS_TAG_NAN) { + ret = 0; + } else if (a == b) { ret = 1; } else if (mjs_is_number(a) && mjs_is_number(b)) { /* @@ -12323,6 +12336,15 @@ mjs_val_t mjs_mk_function(struct mjs *mjs, size_t off) { int mjs_is_function(mjs_val_t v) { return (v & MJS_TAG_MASK) == MJS_TAG_FUNCTION; } + +MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs) { + mjs_val_t ret = MJS_UNDEFINED; + mjs_val_t val = mjs_arg(mjs, 0); + + ret = mjs_mk_boolean(mjs, val == MJS_TAG_NAN); + + mjs_return(mjs, ret); +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_string.c" #endif diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index fde09e9..45ded8b 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -151,4 +151,10 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { v = mjs_mk_object(mjs); mjs_set(mjs, v, "create", ~0, mjs_mk_foreign(mjs, mjs_op_create_object)); mjs_set(mjs, obj, "Object", ~0, v); + + /* + * Populate numeric stuff + */ + mjs_set(mjs, obj, "NaN", ~0, MJS_TAG_NAN); + mjs_set(mjs, obj, "isNaN", ~0, mjs_mk_foreign(mjs, mjs_op_isnan)); } diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 3a2d190..d110613 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -173,7 +173,9 @@ static void op_assign(struct mjs *mjs, int op) { static int check_equal(struct mjs *mjs, mjs_val_t a, mjs_val_t b) { int ret = 0; - if (a == b) { + if (a == MJS_TAG_NAN && b == MJS_TAG_NAN) { + ret = 0; + } else if (a == b) { ret = 1; } else if (mjs_is_number(a) && mjs_is_number(b)) { /* diff --git a/mjs/src/mjs_primitive.c b/mjs/src/mjs_primitive.c index 807dd78..a7108c6 100644 --- a/mjs/src/mjs_primitive.c +++ b/mjs/src/mjs_primitive.c @@ -139,3 +139,12 @@ mjs_val_t mjs_mk_function(struct mjs *mjs, size_t off) { int mjs_is_function(mjs_val_t v) { return (v & MJS_TAG_MASK) == MJS_TAG_FUNCTION; } + +MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs) { + mjs_val_t ret = MJS_UNDEFINED; + mjs_val_t val = mjs_arg(mjs, 0); + + ret = mjs_mk_boolean(mjs, val == MJS_TAG_NAN); + + mjs_return(mjs, ret); +} diff --git a/mjs/src/mjs_primitive.h b/mjs/src/mjs_primitive.h index 3ea1e80..0abce7f 100644 --- a/mjs/src/mjs_primitive.h +++ b/mjs/src/mjs_primitive.h @@ -29,6 +29,11 @@ MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p); */ MJS_PRIVATE void *get_ptr(mjs_val_t v); +/* + * Implementation for JS isNaN() + */ +MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs); + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 1a48c63..fa6abaa 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -166,6 +166,49 @@ const char *test_arithmetic(struct mjs *mjs) { CHECK_NUMERIC("~10", -11); CHECK_NUMERIC("-100", -100); CHECK_NUMERIC("+100", 100); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN", &res)); + ASSERT_EQ(!!isnan(mjs_get_double(mjs, res)), 1); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === NaN", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN !== NaN", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === 0", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === 1", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === null", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === undefined", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === ''", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === {}", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "NaN === []", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "isNaN(NaN)", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + + ASSERT_EXEC_OK(mjs_exec(mjs, "isNaN(NaN * 10)", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + + ASSERT_EXEC_OK(mjs_exec(mjs, "isNaN(0)", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + + ASSERT_EXEC_OK(mjs_exec(mjs, "isNaN('')", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), 0); + mjs_disown(mjs, &res); return NULL; From 7c1266ca94ea60674673ee0c49486a8f7b73f46a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 26 Jul 2017 04:19:48 +0200 Subject: [PATCH 065/265] Fix usleep on ESP8266, add unit test Caused by https://github.com/espressif/ESP8266_NONOS_SDK/issues/31 PUBLISHED_FROM=8966102143dd21704cb12155256c603a02497ad8 --- common/platforms/esp8266/rom/ESP8266_ROM.txt | 13 ++++++++----- common/platforms/esp8266/rom/rom.S | 1 + common/platforms/esp8266/rom/rom.elf | Bin 79956 -> 79984 bytes 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/common/platforms/esp8266/rom/ESP8266_ROM.txt b/common/platforms/esp8266/rom/ESP8266_ROM.txt index 5e638f9..1923cc2 100644 --- a/common/platforms/esp8266/rom/ESP8266_ROM.txt +++ b/common/platforms/esp8266/rom/ESP8266_ROM.txt @@ -4712,8 +4712,11 @@ Disassembly of section .text: 40002ebf: 0108 l32i.n a0, a1, 0 40002ec1: 10c112 addi a1, a1, 16 40002ec4: f00d ret.n -40002ec6: 040000 extui a0, a0, 0, 1 -40002ec9: 3fffc7 bbsi a15, 28, 40002f0c + ... + +40002ec8 <_p_cpu_freq>: +40002ec8: ffc704 excw +40002ecb: 3f .byte 0x3f 40002ecc : 40002ecc: f0c112 addi a1, a1, -16 @@ -4722,7 +4725,7 @@ Disassembly of section .text: 40002ed4: 0109 s32i.n a0, a1, 0 40002ed6: 02cd mov.n a12, a2 40002ed8: 0ae5c5 call0 4000dd38 -40002edb: fffb01 l32r a0, 40002ec8 +40002edb: fffb01 l32r a0, 40002ec8 <_p_cpu_freq> 40002ede: 0008 l32i.n a0, a0, 0 40002ee0: 02dd mov.n a13, a2 40002ee2: 82c0c0 mull a12, a0, a12 @@ -4740,13 +4743,13 @@ Disassembly of section .text: ... 40002f04 : -40002f04: fff131 l32r a3, 40002ec8 +40002f04: fff131 l32r a3, 40002ec8 <_p_cpu_freq> 40002f07: 0329 s32i.n a2, a3, 0 40002f09: f00d ret.n ... 40002f0c : -40002f0c: ffef21 l32r a2, 40002ec8 +40002f0c: ffef21 l32r a2, 40002ec8 <_p_cpu_freq> 40002f0f: 0228 l32i.n a2, a2, 0 40002f11: f00d ret.n ... diff --git a/common/platforms/esp8266/rom/rom.S b/common/platforms/esp8266/rom/rom.S index 784b486..ac27596 100644 --- a/common/platforms/esp8266/rom/rom.S +++ b/common/platforms/esp8266/rom/rom.S @@ -56,6 +56,7 @@ PROVIDE(_c_0xffdfffff, 0x400025dc) PROVIDE(_l_rr_not_dsleep, 0x40002624) PROVIDE(_c_100000, 0x40002664) PROVIDE(_c_0x3feffe00, 0x40002e5c) +PROVIDE(_p_cpu_freq, 0x40002ec8) PROVIDE(_x_wdt_interval, 0x40002f14) // arg: 3 -> 11, 6 -> 12, 12 -> 13 PROVIDE(_p_wdt_cfg, 0x40002f30) PROVIDE(_wdt_soft_timer_fn2, 0x40002f3c) diff --git a/common/platforms/esp8266/rom/rom.elf b/common/platforms/esp8266/rom/rom.elf index a9ceeb7a35acf7ddd9ea2cc36dc7735320772595..6a21116b321780589032452c7854e66d5b333804 100755 GIT binary patch delta 715 zcmYk)PbhF6ylP3=qU=JcDMVW>9Q=D}OHMC02g&V~TqJSV zyeTcQgM*Ti0}eYmaM=z{9DFy2=lR_}-{<@M`W=4HC3mUh-VdnB?O-mbHZ<$Li=tFL ziq3pQEg`l8hlOw90pS;TO1KQCgc~%XjIaUk2#;uF(SZnNP&g7^feXT0@Tag{>4*8j zr?6Kz2d9MZ;NxEIKWY|HUIaxHUWLnWhrtWfN^~OZfv<#{V55)wZE#|c-3ebu+5HxR z8xf4b@4}0)KgJ82a6ot$UJ^cp3q#yLhku1H;m9!07YYb6aSoo~hXnf#4v(`xVDAL` z8!pbWU3%p+sc7{}ks?pkWdG<&tJD97_7~7dq0F)wN~h!IXtsOR>G7*QpVv&L&1`ah feQwRk8*18BZ(^kumtEMwh|+5ezoK?K7E#TA2T@r= delta 710 zcmYk)F-XHu5C-6T7z8^N5ov6Y7CJbYfDsB-tWlw(LPZ_KU{?b|1CG&65K6ZyWDzHI z6Eq4Uf^`wWrBmtP(m|&Vf=dQ}0&;iT_rL!hZ+L@&)){EcoGKmVZ}aLv55`O?Q!9p08VxdiZ{MudocfAauSAZa8kwkPtIeSiH%l~(n{Hb3MU~AI N3`OIJ{s+6s`~kc#Q^)`S From 21373ef713dc04fbfde229a054d38c1e68111bea Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Jul 2017 13:09:33 +0200 Subject: [PATCH 066/265] Add automated check for extern "C" Fix headers that didn't have it PUBLISHED_FROM=ce8140783d4b661f16278a4a5adc957b21965473 --- common.mk | 2 +- common/mg_mem.h | 8 +++++ common/platforms/esp8266/stubs/uart.h | 2 +- common/platforms/platform_cc3100.h | 2 +- common/platforms/platform_esp8266.h | 4 +-- common/platforms/platform_msp432.h | 3 +- common/platforms/platform_nrf51.h | 8 ++--- common/platforms/platform_nrf52.h | 10 +++--- common/platforms/platform_nxp_lpc.h | 3 +- common/platforms/platform_pic32.h | 2 +- common/platforms/platform_tm4c129.h | 16 ++++----- common/platforms/platform_wince.h | 6 ++-- common/test_util.h | 8 +++++ frozen/frozen.h | 2 +- mjs.c | 49 ++++++++++++++++----------- 15 files changed, 76 insertions(+), 49 deletions(-) diff --git a/common.mk b/common.mk index 957363c..75d43dc 100644 --- a/common.mk +++ b/common.mk @@ -36,7 +36,7 @@ else endif format: - @echo "Formatting $$(basename $(CURDIR))" + @echo "Formatting $$(basename $(CURDIR)) $(REPO_ROOT)" @test -d "$(REPO_ROOT)" && true || { echo "Define REPO_ROOT Makefile variable, REPO_ROOT/common.mk wants it." ; false ; } @git --git-dir $(REPO_ABS_PATH)/.git --work-tree $(REPO_ROOT) \ ls-files --full-name $(FORMAT_FILES) | \ diff --git a/common/mg_mem.h b/common/mg_mem.h index 3efdc3b..65d71c7 100644 --- a/common/mg_mem.h +++ b/common/mg_mem.h @@ -6,6 +6,10 @@ #ifndef CS_COMMON_MG_MEM_H_ #define CS_COMMON_MG_MEM_H_ +#ifdef __cplusplus +extern "C" { +#endif + #ifndef MG_MALLOC #define MG_MALLOC malloc #endif @@ -22,4 +26,8 @@ #define MG_FREE free #endif +#ifdef __cplusplus +} +#endif + #endif /* CS_COMMON_MG_MEM_H_ */ diff --git a/common/platforms/esp8266/stubs/uart.h b/common/platforms/esp8266/stubs/uart.h index 49b0a37..fc321c2 100644 --- a/common/platforms/esp8266/stubs/uart.h +++ b/common/platforms/esp8266/stubs/uart.h @@ -10,7 +10,7 @@ void set_baud_rate(uint32_t uart_no, uint32_t baud_rate); -#define REG_UART_BASE(i) (0x60000000 + (i) * 0xf00) +#define REG_UART_BASE(i) (0x60000000 + (i) *0xf00) #define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0) #define UART_CONF1_REG(i) (REG_UART_BASE(i) + 0x24) #define UART_RX_TOUT_EN (BIT(31)) diff --git a/common/platforms/platform_cc3100.h b/common/platforms/platform_cc3100.h index c7e995c..ba07f22 100644 --- a/common/platforms/platform_cc3100.h +++ b/common/platforms/platform_cc3100.h @@ -26,7 +26,7 @@ #include #include -#undef timeval +#undef timeval typedef int sock_t; #define INVALID_SOCKET (-1) diff --git a/common/platforms/platform_esp8266.h b/common/platforms/platform_esp8266.h index 6a4d547..88d02ff 100644 --- a/common/platforms/platform_esp8266.h +++ b/common/platforms/platform_esp8266.h @@ -41,9 +41,9 @@ typedef struct stat cs_stat_t; #ifndef MG_NET_IF #include #if LWIP_SOCKET /* RTOS SDK has LWIP sockets */ -# define MG_NET_IF MG_NET_IF_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET #else -# define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL #endif #endif diff --git a/common/platforms/platform_msp432.h b/common/platforms/platform_msp432.h index eccea91..d8cf16a 100644 --- a/common/platforms/platform_msp432.h +++ b/common/platforms/platform_msp432.h @@ -92,7 +92,8 @@ int _stat(const char *pathname, struct stat *st); #define CS_ENABLE_STDIO 1 #endif -#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && !defined(MG_ENABLE_FILESYSTEM) +#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ + !defined(MG_ENABLE_FILESYSTEM) #define MG_ENABLE_FILESYSTEM 1 #endif diff --git a/common/platforms/platform_nrf51.h b/common/platforms/platform_nrf51.h index c678b44..55f89dd 100644 --- a/common/platforms/platform_nrf51.h +++ b/common/platforms/platform_nrf51.h @@ -15,16 +15,16 @@ #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 /* * For ARM C Compiler, make lwip to export `struct timeval`; for other * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #else struct timeval; int gettimeofday(struct timeval *tp, void *tzp); diff --git a/common/platforms/platform_nrf52.h b/common/platforms/platform_nrf52.h index 0e1abbc..5828903 100644 --- a/common/platforms/platform_nrf52.h +++ b/common/platforms/platform_nrf52.h @@ -16,12 +16,12 @@ #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 #if !defined(ENOSPC) -# define ENOSPC 28 /* No space left on device */ +#define ENOSPC 28 /* No space left on device */ #endif /* @@ -29,7 +29,7 @@ * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #endif #define INT64_FMT PRId64 diff --git a/common/platforms/platform_nxp_lpc.h b/common/platforms/platform_nxp_lpc.h index 69372b6..cf9b7e7 100644 --- a/common/platforms/platform_nxp_lpc.h +++ b/common/platforms/platform_nxp_lpc.h @@ -23,7 +23,8 @@ typedef struct stat cs_stat_t; #define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL /* - * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and Redlib. + * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and + *Redlib. * See https://community.nxp.com/message/630860 for more details. * * Redlib is the default and lacks certain things, so we provide them. diff --git a/common/platforms/platform_pic32.h b/common/platforms/platform_pic32.h index a23197e..b568025 100644 --- a/common/platforms/platform_pic32.h +++ b/common/platforms/platform_pic32.h @@ -30,7 +30,7 @@ typedef TCP_SOCKET sock_t; #define CS_ENABLE_STDIO 1 #endif -char* inet_ntoa(struct in_addr in); +char *inet_ntoa(struct in_addr in); #endif /* CS_PLATFORM == CS_P_PIC32 */ diff --git a/common/platforms/platform_tm4c129.h b/common/platforms/platform_tm4c129.h index 2d893da..5e87b94 100644 --- a/common/platforms/platform_tm4c129.h +++ b/common/platforms/platform_tm4c129.h @@ -29,15 +29,15 @@ typedef struct stat cs_stat_t; #define __cdecl #ifndef MG_NET_IF -# include -# if LWIP_SOCKET -# define MG_NET_IF MG_NET_IF_SOCKET -# else -# define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -# endif -# define MG_LWIP 1 +#include +#if LWIP_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET +#else +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#endif +#define MG_LWIP 1 #elif MG_NET_IF == MG_NET_IF_SIMPLELINK -# include "common/platforms/simplelink/cs_simplelink.h" +#include "common/platforms/simplelink/cs_simplelink.h" #endif #ifndef CS_ENABLE_STDIO diff --git a/common/platforms/platform_wince.h b/common/platforms/platform_wince.h index a33f0c8..48c51f6 100644 --- a/common/platforms/platform_wince.h +++ b/common/platforms/platform_wince.h @@ -179,18 +179,18 @@ typedef struct _stati64 { #endif #ifndef _UINTPTR_T_DEFINED -typedef unsigned int* uintptr_t; +typedef unsigned int *uintptr_t; #endif #define _S_IFREG 2 #define _S_IFDIR 4 #ifndef S_ISDIR -#define S_ISDIR(x) (((x) & _S_IFDIR) != 0) +#define S_ISDIR(x) (((x) &_S_IFDIR) != 0) #endif #ifndef S_ISREG -#define S_ISREG(x) (((x) & _S_IFREG) != 0) +#define S_ISREG(x) (((x) &_S_IFREG) != 0) #endif int open(const char *filename, int oflag, int pmode); diff --git a/common/test_util.h b/common/test_util.h index 4cd0501..7276f9a 100644 --- a/common/test_util.h +++ b/common/test_util.h @@ -23,6 +23,10 @@ #include "common/cs_time.h" +#ifdef __cplusplus +extern "C" { +#endif + extern int num_tests; #ifdef MG_TEST_ABORT_ON_FAIL @@ -171,4 +175,8 @@ void poll_until(struct mg_mgr *mgr, double timeout, int (*cond)(void *, void *), void *cond_arg1, void *cond_arg2); #endif +#ifdef __cplusplus +} +#endif + #endif /* CS_COMMON_TEST_UTIL_H_ */ diff --git a/frozen/frozen.h b/frozen/frozen.h index 803d74f..3ac3a98 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -171,7 +171,7 @@ int json_printf_array(struct json_out *, va_list *ap); * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" * 2. Order of keys in an object is irrelevant. * 3. Several extra format specifiers are supported: - * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), + * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), * expects boolean `true` or `false`. * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned * string is malloc-ed, caller must free() the string. diff --git a/mjs.c b/mjs.c index 2d24a96..3d36427 100644 --- a/mjs.c +++ b/mjs.c @@ -528,9 +528,9 @@ typedef struct stat cs_stat_t; #ifndef MG_NET_IF #include #if LWIP_SOCKET /* RTOS SDK has LWIP sockets */ -# define MG_NET_IF MG_NET_IF_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET #else -# define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL #endif #endif @@ -800,7 +800,7 @@ int stat(const char *pathname, struct stat *st); #include #include -#undef timeval +#undef timeval typedef int sock_t; #define INVALID_SOCKET (-1) @@ -922,16 +922,16 @@ in_addr_t inet_addr(const char *cp); #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 /* * For ARM C Compiler, make lwip to export `struct timeval`; for other * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #else struct timeval; int gettimeofday(struct timeval *tp, void *tzp); @@ -968,12 +968,12 @@ int gettimeofday(struct timeval *tp, void *tzp); #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 #if !defined(ENOSPC) -# define ENOSPC 28 /* No space left on device */ +#define ENOSPC 28 /* No space left on device */ #endif /* @@ -981,7 +981,7 @@ int gettimeofday(struct timeval *tp, void *tzp); * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #endif #define INT64_FMT PRId64 @@ -1178,18 +1178,18 @@ typedef struct _stati64 { #endif #ifndef _UINTPTR_T_DEFINED -typedef unsigned int* uintptr_t; +typedef unsigned int *uintptr_t; #endif #define _S_IFREG 2 #define _S_IFDIR 4 #ifndef S_ISDIR -#define S_ISDIR(x) (((x) & _S_IFDIR) != 0) +#define S_ISDIR(x) (((x) &_S_IFDIR) != 0) #endif #ifndef S_ISREG -#define S_ISREG(x) (((x) & _S_IFREG) != 0) +#define S_ISREG(x) (((x) &_S_IFREG) != 0) #endif int open(const char *filename, int oflag, int pmode); @@ -1226,7 +1226,8 @@ typedef struct stat cs_stat_t; #define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL /* - * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and Redlib. + * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and + *Redlib. * See https://community.nxp.com/message/630860 for more details. * * Redlib is the default and lacks certain things, so we provide them. @@ -1322,7 +1323,7 @@ typedef TCP_SOCKET sock_t; #define CS_ENABLE_STDIO 1 #endif -char* inet_ntoa(struct in_addr in); +char *inet_ntoa(struct in_addr in); #endif /* CS_PLATFORM == CS_P_PIC32 */ @@ -1498,7 +1499,7 @@ double cs_time(void); #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* Describes chunk of memory */ struct mg_str { @@ -1552,7 +1553,7 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif #endif /* CS_COMMON_MG_STR_H_ */ #ifdef MJS_MODULE_LINES @@ -1850,6 +1851,10 @@ void mbuf_trim(struct mbuf *); #ifndef CS_COMMON_MG_MEM_H_ #define CS_COMMON_MG_MEM_H_ +#ifdef __cplusplus +extern "C" { +#endif + #ifndef MG_MALLOC #define MG_MALLOC malloc #endif @@ -1866,6 +1871,10 @@ void mbuf_trim(struct mbuf *); #define MG_FREE free #endif +#ifdef __cplusplus +} +#endif + #endif /* CS_COMMON_MG_MEM_H_ */ #ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.h" @@ -4131,7 +4140,7 @@ int json_printf_array(struct json_out *, va_list *ap); * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" * 2. Order of keys in an object is irrelevant. * 3. Several extra format specifiers are supported: - * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), + * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), * expects boolean `true` or `false`. * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned * string is malloc-ed, caller must free() the string. From 2e8c1cdab084016f6370de94d9066f853330fc29 Mon Sep 17 00:00:00 2001 From: Our CI Bot Date: Mon, 14 Aug 2017 13:21:17 +0100 Subject: [PATCH 067/265] Unify number->string conversion logic PUBLISHED_FROM=636388bb9cc126c153620fad51a24e74b1828c39 --- mjs.c | 477 ++++++++++++++++++++------------------- mjs/src/mjs_conversion.c | 13 +- mjs/src/mjs_util.h | 4 + 3 files changed, 250 insertions(+), 244 deletions(-) diff --git a/mjs.c b/mjs.c index 3d36427..4dba639 100644 --- a/mjs.c +++ b/mjs.c @@ -3335,6 +3335,236 @@ MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs); #endif /* MJS_STRING_H_ */ #ifdef MJS_MODULE_LINES +#line 1 "frozen/frozen.h" +#endif +/* + * Copyright (c) 2004-2013 Sergey Lyubka + * Copyright (c) 2013 Cesanta Software Limited + * All rights reserved + * + * This library is dual-licensed: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. For the terms of this + * license, see . + * + * You are free to use this library under the terms of the GNU General + * Public License, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * Alternatively, you can license this library under a commercial + * license, as set out in . + */ + +#ifndef CS_FROZEN_FROZEN_H_ +#define CS_FROZEN_FROZEN_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include + +#ifdef _WIN32 +typedef int bool; +#else +#include +#endif + +/* JSON token type */ +enum json_token_type { + JSON_TYPE_INVALID = 0, /* memsetting to 0 should create INVALID value */ + JSON_TYPE_STRING, + JSON_TYPE_NUMBER, + JSON_TYPE_TRUE, + JSON_TYPE_FALSE, + JSON_TYPE_NULL, + JSON_TYPE_OBJECT_START, + JSON_TYPE_OBJECT_END, + JSON_TYPE_ARRAY_START, + JSON_TYPE_ARRAY_END, + + JSON_TYPES_CNT +}; + +/* + * Structure containing token type and value. Used in `json_walk()` and + * `json_scanf()` with the format specifier `%T`. + */ +struct json_token { + const char *ptr; /* Points to the beginning of the value */ + int len; /* Value length */ + enum json_token_type type; /* Type of the token, possible values are above */ +}; + +#define JSON_INVALID_TOKEN \ + { 0, 0, JSON_TYPE_INVALID } + +/* Error codes */ +#define JSON_STRING_INVALID -1 +#define JSON_STRING_INCOMPLETE -2 + +/* + * Callback-based SAX-like API. + * + * Property name and length is given only if it's available: i.e. if current + * event is an object's property. In other cases, `name` is `NULL`. For + * example, name is never given: + * - For the first value in the JSON string; + * - For events JSON_TYPE_OBJECT_END and JSON_TYPE_ARRAY_END + * + * E.g. for the input `{ "foo": 123, "bar": [ 1, 2, { "baz": true } ] }`, + * the sequence of callback invocations will be as follows: + * + * - type: JSON_TYPE_OBJECT_START, name: NULL, path: "", value: NULL + * - type: JSON_TYPE_NUMBER, name: "foo", path: ".foo", value: "123" + * - type: JSON_TYPE_ARRAY_START, name: "bar", path: ".bar", value: NULL + * - type: JSON_TYPE_NUMBER, name: "0", path: ".bar[0]", value: "1" + * - type: JSON_TYPE_NUMBER, name: "1", path: ".bar[1]", value: "2" + * - type: JSON_TYPE_OBJECT_START, name: "2", path: ".bar[2]", value: NULL + * - type: JSON_TYPE_TRUE, name: "baz", path: ".bar[2].baz", value: "true" + * - type: JSON_TYPE_OBJECT_END, name: NULL, path: ".bar[2]", value: "{ \"baz\": + *true }" + * - type: JSON_TYPE_ARRAY_END, name: NULL, path: ".bar", value: "[ 1, 2, { + *\"baz\": true } ]" + * - type: JSON_TYPE_OBJECT_END, name: NULL, path: "", value: "{ \"foo\": 123, + *\"bar\": [ 1, 2, { \"baz\": true } ] }" + */ +typedef void (*json_walk_callback_t)(void *callback_data, const char *name, + size_t name_len, const char *path, + const struct json_token *token); + +/* + * Parse `json_string`, invoking `callback` in a way similar to SAX parsers; + * see `json_walk_callback_t`. + */ +int json_walk(const char *json_string, int json_string_length, + json_walk_callback_t callback, void *callback_data); + +/* + * JSON generation API. + * struct json_out abstracts output, allowing alternative printing plugins. + */ +struct json_out { + int (*printer)(struct json_out *, const char *str, size_t len); + union { + struct { + char *buf; + size_t size; + size_t len; + } buf; + void *data; + FILE *fp; + } u; +}; + +extern int json_printer_buf(struct json_out *, const char *, size_t); +extern int json_printer_file(struct json_out *, const char *, size_t); + +#define JSON_OUT_BUF(buf, len) \ + { \ + json_printer_buf, { \ + { buf, len, 0 } \ + } \ + } +#define JSON_OUT_FILE(fp) \ + { \ + json_printer_file, { \ + { (void *) fp, 0, 0 } \ + } \ + } + +typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); + +/* + * Generate formatted output into a given sting buffer. + * This is a superset of printf() function, with extra format specifiers: + * - `%B` print json boolean, `true` or `false`. Accepts an `int`. + * - `%Q` print quoted escaped string or `null`. Accepts a `const char *`. + * - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *` + * - `%V` print quoted base64-encoded string. Accepts a `const char *`, `int`. + * - `%H` print quoted hex-encoded string. Accepts a `int`, `const char *`. + * - `%M` invokes a json_printf_callback_t function. That callback function + * can consume more parameters. + * + * Return number of bytes printed. If the return value is bigger then the + * supplied buffer, that is an indicator of overflow. In the overflow case, + * overflown bytes are not printed. + */ +int json_printf(struct json_out *, const char *fmt, ...); +int json_vprintf(struct json_out *, const char *fmt, va_list ap); + +/* + * Helper %M callback that prints contiguous C arrays. + * Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt + * Return number of bytes printed. + */ +int json_printf_array(struct json_out *, va_list *ap); + +/* + * Scan JSON string `str`, performing scanf-like conversions according to `fmt`. + * This is a `scanf()` - like function, with following differences: + * + * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" + * 2. Order of keys in an object is irrelevant. + * 3. Several extra format specifiers are supported: + * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), + * expects boolean `true` or `false`. + * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned + * string is malloc-ed, caller must free() the string. + * - %V: consumes `char **`, `int *`. Expects base64-encoded string. + * Result string is base64-decoded, malloced and NUL-terminated. + * The length of result string is stored in `int *` placeholder. + * Caller must free() the result. + * - %H: consumes `int *`, `char **`. + * Expects a hex-encoded string, e.g. "fa014f". + * Result string is hex-decoded, malloced and NUL-terminated. + * The length of the result string is stored in `int *` placeholder. + * Caller must free() the result. + * - %M: consumes custom scanning function pointer and + * `void *user_data` parameter - see json_scanner_t definition. + * - %T: consumes `struct json_token *`, fills it out with matched token. + * + * Return number of elements successfully scanned & converted. + * Negative number means scan error. + */ +int json_scanf(const char *str, int str_len, const char *fmt, ...); +int json_vscanf(const char *str, int str_len, const char *fmt, va_list ap); + +/* json_scanf's %M handler */ +typedef void (*json_scanner_t)(const char *str, int len, void *user_data); + +/* + * Helper function to scan array item with given path and index. + * Fills `token` with the matched JSON token. + * Return 0 if no array element found, otherwise non-0. + */ +int json_scanf_array_elem(const char *s, int len, const char *path, int index, + struct json_token *token); + +/* + * Unescape JSON-encoded string src,slen into dst, dlen. + * src and dst may overlap. + * If destination buffer is too small (or zero-length), result string is not + * written but the length is counted nevertheless (similar to snprintf). + * Return the length of unescaped string in bytes. + */ +int json_unescape(const char *src, int slen, char *dst, int dlen); + +/* + * Escape a string `str`, `str_len` into the printer `out`. + * Return the number of bytes printed. + */ +int json_escape(struct json_out *out, const char *str, size_t str_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_FROZEN_FROZEN_H_ */ +#ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_util_public.h" #endif /* @@ -3398,6 +3628,7 @@ int mjs_get_offset_by_call_frame_num(struct mjs *mjs, int cf_num); #ifndef MJS_UTIL_H_ #define MJS_UTIL_H_ +/* Amalgamated: #include "frozen/frozen.h" */ /* Amalgamated: #include "mjs/src/mjs_core.h" */ /* Amalgamated: #include "mjs/src/mjs_util_public.h" */ @@ -3433,6 +3664,9 @@ MJS_PRIVATE int mjs_normalize_idx(int idx, int size); MJS_PRIVATE const char *mjs_get_bcode_filename(struct mjs *mjs, struct mjs_bcode_part *bp); +/* Print JS value `v` to the JSON stream `out`. */ +void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -3964,236 +4198,6 @@ mjs_parse(const char *path, const char *buf, struct mjs *); #endif /* __cplusplus */ #endif /* MJS_PARSER_H */ -#ifdef MJS_MODULE_LINES -#line 1 "frozen/frozen.h" -#endif -/* - * Copyright (c) 2004-2013 Sergey Lyubka - * Copyright (c) 2013 Cesanta Software Limited - * All rights reserved - * - * This library is dual-licensed: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. For the terms of this - * license, see . - * - * You are free to use this library under the terms of the GNU General - * Public License, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * Alternatively, you can license this library under a commercial - * license, as set out in . - */ - -#ifndef CS_FROZEN_FROZEN_H_ -#define CS_FROZEN_FROZEN_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include -#include -#include - -#ifdef _WIN32 -typedef int bool; -#else -#include -#endif - -/* JSON token type */ -enum json_token_type { - JSON_TYPE_INVALID = 0, /* memsetting to 0 should create INVALID value */ - JSON_TYPE_STRING, - JSON_TYPE_NUMBER, - JSON_TYPE_TRUE, - JSON_TYPE_FALSE, - JSON_TYPE_NULL, - JSON_TYPE_OBJECT_START, - JSON_TYPE_OBJECT_END, - JSON_TYPE_ARRAY_START, - JSON_TYPE_ARRAY_END, - - JSON_TYPES_CNT -}; - -/* - * Structure containing token type and value. Used in `json_walk()` and - * `json_scanf()` with the format specifier `%T`. - */ -struct json_token { - const char *ptr; /* Points to the beginning of the value */ - int len; /* Value length */ - enum json_token_type type; /* Type of the token, possible values are above */ -}; - -#define JSON_INVALID_TOKEN \ - { 0, 0, JSON_TYPE_INVALID } - -/* Error codes */ -#define JSON_STRING_INVALID -1 -#define JSON_STRING_INCOMPLETE -2 - -/* - * Callback-based SAX-like API. - * - * Property name and length is given only if it's available: i.e. if current - * event is an object's property. In other cases, `name` is `NULL`. For - * example, name is never given: - * - For the first value in the JSON string; - * - For events JSON_TYPE_OBJECT_END and JSON_TYPE_ARRAY_END - * - * E.g. for the input `{ "foo": 123, "bar": [ 1, 2, { "baz": true } ] }`, - * the sequence of callback invocations will be as follows: - * - * - type: JSON_TYPE_OBJECT_START, name: NULL, path: "", value: NULL - * - type: JSON_TYPE_NUMBER, name: "foo", path: ".foo", value: "123" - * - type: JSON_TYPE_ARRAY_START, name: "bar", path: ".bar", value: NULL - * - type: JSON_TYPE_NUMBER, name: "0", path: ".bar[0]", value: "1" - * - type: JSON_TYPE_NUMBER, name: "1", path: ".bar[1]", value: "2" - * - type: JSON_TYPE_OBJECT_START, name: "2", path: ".bar[2]", value: NULL - * - type: JSON_TYPE_TRUE, name: "baz", path: ".bar[2].baz", value: "true" - * - type: JSON_TYPE_OBJECT_END, name: NULL, path: ".bar[2]", value: "{ \"baz\": - *true }" - * - type: JSON_TYPE_ARRAY_END, name: NULL, path: ".bar", value: "[ 1, 2, { - *\"baz\": true } ]" - * - type: JSON_TYPE_OBJECT_END, name: NULL, path: "", value: "{ \"foo\": 123, - *\"bar\": [ 1, 2, { \"baz\": true } ] }" - */ -typedef void (*json_walk_callback_t)(void *callback_data, const char *name, - size_t name_len, const char *path, - const struct json_token *token); - -/* - * Parse `json_string`, invoking `callback` in a way similar to SAX parsers; - * see `json_walk_callback_t`. - */ -int json_walk(const char *json_string, int json_string_length, - json_walk_callback_t callback, void *callback_data); - -/* - * JSON generation API. - * struct json_out abstracts output, allowing alternative printing plugins. - */ -struct json_out { - int (*printer)(struct json_out *, const char *str, size_t len); - union { - struct { - char *buf; - size_t size; - size_t len; - } buf; - void *data; - FILE *fp; - } u; -}; - -extern int json_printer_buf(struct json_out *, const char *, size_t); -extern int json_printer_file(struct json_out *, const char *, size_t); - -#define JSON_OUT_BUF(buf, len) \ - { \ - json_printer_buf, { \ - { buf, len, 0 } \ - } \ - } -#define JSON_OUT_FILE(fp) \ - { \ - json_printer_file, { \ - { (void *) fp, 0, 0 } \ - } \ - } - -typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); - -/* - * Generate formatted output into a given sting buffer. - * This is a superset of printf() function, with extra format specifiers: - * - `%B` print json boolean, `true` or `false`. Accepts an `int`. - * - `%Q` print quoted escaped string or `null`. Accepts a `const char *`. - * - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *` - * - `%V` print quoted base64-encoded string. Accepts a `const char *`, `int`. - * - `%H` print quoted hex-encoded string. Accepts a `int`, `const char *`. - * - `%M` invokes a json_printf_callback_t function. That callback function - * can consume more parameters. - * - * Return number of bytes printed. If the return value is bigger then the - * supplied buffer, that is an indicator of overflow. In the overflow case, - * overflown bytes are not printed. - */ -int json_printf(struct json_out *, const char *fmt, ...); -int json_vprintf(struct json_out *, const char *fmt, va_list ap); - -/* - * Helper %M callback that prints contiguous C arrays. - * Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt - * Return number of bytes printed. - */ -int json_printf_array(struct json_out *, va_list *ap); - -/* - * Scan JSON string `str`, performing scanf-like conversions according to `fmt`. - * This is a `scanf()` - like function, with following differences: - * - * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" - * 2. Order of keys in an object is irrelevant. - * 3. Several extra format specifiers are supported: - * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), - * expects boolean `true` or `false`. - * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned - * string is malloc-ed, caller must free() the string. - * - %V: consumes `char **`, `int *`. Expects base64-encoded string. - * Result string is base64-decoded, malloced and NUL-terminated. - * The length of result string is stored in `int *` placeholder. - * Caller must free() the result. - * - %H: consumes `int *`, `char **`. - * Expects a hex-encoded string, e.g. "fa014f". - * Result string is hex-decoded, malloced and NUL-terminated. - * The length of the result string is stored in `int *` placeholder. - * Caller must free() the result. - * - %M: consumes custom scanning function pointer and - * `void *user_data` parameter - see json_scanner_t definition. - * - %T: consumes `struct json_token *`, fills it out with matched token. - * - * Return number of elements successfully scanned & converted. - * Negative number means scan error. - */ -int json_scanf(const char *str, int str_len, const char *fmt, ...); -int json_vscanf(const char *str, int str_len, const char *fmt, va_list ap); - -/* json_scanf's %M handler */ -typedef void (*json_scanner_t)(const char *str, int len, void *user_data); - -/* - * Helper function to scan array item with given path and index. - * Fills `token` with the matched JSON token. - * Return 0 if no array element found, otherwise non-0. - */ -int json_scanf_array_elem(const char *s, int len, const char *path, int index, - struct json_token *token); - -/* - * Unescape JSON-encoded string src,slen into dst, dlen. - * src and dst may overlap. - * If destination buffer is too small (or zero-length), result string is not - * written but the length is counted nevertheless (similar to snprintf). - * Return the length of unescaped string in bytes. - */ -int json_unescape(const char *src, int slen, char *dst, int dlen); - -/* - * Escape a string `str`, `str_len` into the printer `out`. - * Return the number of bytes printed. - */ -int json_escape(struct json_out *out, const char *str, size_t str_len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_FROZEN_FROZEN_H_ */ #ifndef MJS_EXPORT_INTERNAL_HEADERS #ifdef MJS_MODULE_LINES #line 1 "common/cs_dbg.c" @@ -7149,6 +7153,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { /* Amalgamated: #include "mjs/src/mjs_object.h" */ /* Amalgamated: #include "mjs/src/mjs_primitive.h" */ /* Amalgamated: #include "mjs/src/mjs_string.h" */ +/* Amalgamated: #include "mjs/src/mjs_util.h" */ MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p, size_t *sizep, int *need_free) { @@ -7161,17 +7166,15 @@ MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p, if (mjs_is_string(*v)) { *p = (char *) mjs_get_string(mjs, v, sizep); } else if (mjs_is_number(*v)) { - double num = mjs_get_double(mjs, *v); - const char *fmt = num > 1e10 ? "%.21g" : "%.10g"; - (void) num; - (void) fmt; - *sizep = snprintf(NULL, 0, fmt, num); - *p = malloc(*sizep + 1 /*null term*/); + char buf[50] = ""; + struct json_out out = JSON_OUT_BUF(buf, sizeof(buf)); + mjs_jprintf(*v, mjs, &out); + *sizep = strlen(buf); + *p = strdup(buf); if (*p == NULL) { ret = MJS_OUT_OF_MEMORY; goto clean; } - snprintf(*p, *sizep + 1, fmt, num); *need_free = 1; } else if (mjs_is_boolean(*v)) { if (mjs_get_bool(mjs, *v)) { diff --git a/mjs/src/mjs_conversion.c b/mjs/src/mjs_conversion.c index 890dd3b..98317ac 100644 --- a/mjs/src/mjs_conversion.c +++ b/mjs/src/mjs_conversion.c @@ -7,6 +7,7 @@ #include "mjs/src/mjs_object.h" #include "mjs/src/mjs_primitive.h" #include "mjs/src/mjs_string.h" +#include "mjs/src/mjs_util.h" MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p, size_t *sizep, int *need_free) { @@ -19,17 +20,15 @@ MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p, if (mjs_is_string(*v)) { *p = (char *) mjs_get_string(mjs, v, sizep); } else if (mjs_is_number(*v)) { - double num = mjs_get_double(mjs, *v); - const char *fmt = num > 1e10 ? "%.21g" : "%.10g"; - (void) num; - (void) fmt; - *sizep = snprintf(NULL, 0, fmt, num); - *p = malloc(*sizep + 1 /*null term*/); + char buf[50] = ""; + struct json_out out = JSON_OUT_BUF(buf, sizeof(buf)); + mjs_jprintf(*v, mjs, &out); + *sizep = strlen(buf); + *p = strdup(buf); if (*p == NULL) { ret = MJS_OUT_OF_MEMORY; goto clean; } - snprintf(*p, *sizep + 1, fmt, num); *need_free = 1; } else if (mjs_is_boolean(*v)) { if (mjs_get_bool(mjs, *v)) { diff --git a/mjs/src/mjs_util.h b/mjs/src/mjs_util.h index 7125eee..a8f1b03 100644 --- a/mjs/src/mjs_util.h +++ b/mjs/src/mjs_util.h @@ -6,6 +6,7 @@ #ifndef MJS_UTIL_H_ #define MJS_UTIL_H_ +#include "frozen/frozen.h" #include "mjs/src/mjs_core.h" #include "mjs/src/mjs_util_public.h" @@ -41,6 +42,9 @@ MJS_PRIVATE int mjs_normalize_idx(int idx, int size); MJS_PRIVATE const char *mjs_get_bcode_filename(struct mjs *mjs, struct mjs_bcode_part *bp); +/* Print JS value `v` to the JSON stream `out`. */ +void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out); + #if defined(__cplusplus) } #endif /* __cplusplus */ From 01536c6d1b084fedc4cca3cfbecd8856dc715792 Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Wed, 16 Aug 2017 22:24:07 +0500 Subject: [PATCH 068/265] Fix Nmap reset on ESP8266 PUBLISHED_FROM=7b9c85e7708721f2c6d0e2fc8ad5c32c61b48854 --- common/platforms/lwip/mg_lwip_net_if.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index c33e37b..a6b93e3 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -371,6 +371,7 @@ static void tcp_close_tcpip(void *arg) { void mg_lwip_handle_accept(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (cs->pcb.tcp == NULL) return; #if MG_ENABLE_SSL if (cs->lc->flags & MG_F_SSL) { if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) { From d01ba6db8a73e85a8b81c23d3ea6899c068be6a8 Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Thu, 17 Aug 2017 15:07:45 +0100 Subject: [PATCH 069/265] Implement rmdir & sleep func instead macros PUBLISHED_FROM=62c73e5fb4f70e2b5b8824ce092012508640b173 --- common/platforms/platform_windows.h | 5 +++-- common/platforms/windows/windows_direct.c | 17 +++++++++++++++++ mjs.c | 5 +++-- 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 common/platforms/windows/windows_direct.c diff --git a/common/platforms/platform_windows.h b/common/platforms/platform_windows.h index d8e7d2a..7b0d655 100644 --- a/common/platforms/platform_windows.h +++ b/common/platforms/platform_windows.h @@ -67,14 +67,12 @@ #endif #define snprintf _snprintf #define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) *1000) #define to64(x) _atoi64(x) #if !defined(__MINGW32__) && !defined(__MINGW64__) #define popen(x, y) _popen((x), (y)) #define pclose(x) _pclose(x) #define fileno _fileno #endif -#define rmdir _rmdir #if defined(_MSC_VER) && _MSC_VER >= 1400 #define fseeko(x, y, z) _fseeki64((x), (y), (z)) #else @@ -165,5 +163,8 @@ typedef struct _stati64 cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif +int rmdir(const char *dirname); +unsigned int sleep(unsigned int seconds); + #endif /* CS_PLATFORM == CS_P_WINDOWS */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ diff --git a/common/platforms/windows/windows_direct.c b/common/platforms/windows/windows_direct.c new file mode 100644 index 0000000..8932899 --- /dev/null +++ b/common/platforms/windows/windows_direct.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2017 Cesanta Software Limited + * All rights reserved + */ + +#ifdef _WIN32 + +int rmdir(const char *dirname) { + return _rmdir(dirname); +} + +unsigned int sleep(unsigned int seconds) { + Sleep(seconds * 1000); + return 0; +} + +#endif /* _WIN32 */ diff --git a/mjs.c b/mjs.c index 4dba639..b107137 100644 --- a/mjs.c +++ b/mjs.c @@ -191,14 +191,12 @@ #endif #define snprintf _snprintf #define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) *1000) #define to64(x) _atoi64(x) #if !defined(__MINGW32__) && !defined(__MINGW64__) #define popen(x, y) _popen((x), (y)) #define pclose(x) _pclose(x) #define fileno _fileno #endif -#define rmdir _rmdir #if defined(_MSC_VER) && _MSC_VER >= 1400 #define fseeko(x, y, z) _fseeki64((x), (y), (z)) #else @@ -289,6 +287,9 @@ typedef struct _stati64 cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif +int rmdir(const char *dirname); +unsigned int sleep(unsigned int seconds); + #endif /* CS_PLATFORM == CS_P_WINDOWS */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ #ifdef MJS_MODULE_LINES From 5897237479a6e9c092b4b6a4808339f0aba1df01 Mon Sep 17 00:00:00 2001 From: Our CI Bot Date: Thu, 17 Aug 2017 20:23:26 +0100 Subject: [PATCH 070/265] Fix https://github.com/cesanta/mjs/issues/44 PUBLISHED_FROM=2b2a992146f8fc645fb33c8473bdf1a1f2a16a24 --- common/mg_str.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ common/mg_str.h | 71 ++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 common/mg_str.c create mode 100644 common/mg_str.h diff --git a/common/mg_str.c b/common/mg_str.c new file mode 100644 index 0000000..7d14ebf --- /dev/null +++ b/common/mg_str.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#include "common/mg_mem.h" +#include "common/mg_str.h" + +#include +#include + +int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK; + +struct mg_str mg_mk_str(const char *s) WEAK; +struct mg_str mg_mk_str(const char *s) { + struct mg_str ret = {s, 0}; + if (s != NULL) ret.len = strlen(s); + return ret; +} + +struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK; +struct mg_str mg_mk_str_n(const char *s, size_t len) { + struct mg_str ret = {s, len}; + return ret; +} + +int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcasecmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +static struct mg_str mg_strdup_common(const struct mg_str s, + int nul_terminate) { + struct mg_str r = {NULL, 0}; + if (s.len > 0 && s.p != NULL) { + char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0)); + if (sc != NULL) { + memcpy(sc, s.p, s.len); + if (nul_terminate) sc[s.len] = '\0'; + r.p = sc; + r.len = s.len; + } + } + return r; +} + +struct mg_str mg_strdup(const struct mg_str s) WEAK; +struct mg_str mg_strdup(const struct mg_str s) { + return mg_strdup_common(s, 0 /* NUL-terminate */); +} + +struct mg_str mg_strdup_nul(const struct mg_str s) WEAK; +struct mg_str mg_strdup_nul(const struct mg_str s) { + return mg_strdup_common(s, 1 /* NUL-terminate */); +} + +const char *mg_strchr(const struct mg_str s, int c) WEAK; +const char *mg_strchr(const struct mg_str s, int c) { + size_t i; + for (i = 0; i < s.len; i++) { + if (s.p[i] == c) return &s.p[i]; + } + return NULL; +} + +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { + size_t i = 0; + while (i < str1.len && i < str2.len) { + if (str1.p[i] < str2.p[i]) return -1; + if (str1.p[i] > str2.p[i]) return 1; + i++; + } + if (i < str1.len) return 1; + if (i < str2.len) return -1; + return 0; +} + +int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK; +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { + struct mg_str s1 = str1; + struct mg_str s2 = str2; + + if (s1.len > n) { + s1.len = n; + } + if (s2.len > n) { + s2.len = n; + } + return mg_strcmp(s1, s2); +} + +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) WEAK; +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) { + size_t i; + if (needle.len > haystack.len) return NULL; + for (i = 0; i <= haystack.len - needle.len; i++) { + if (memcmp(haystack.p + i, needle.p, needle.len) == 0) { + return haystack.p + i; + } + } + return NULL; +} diff --git a/common/mg_str.h b/common/mg_str.h new file mode 100644 index 0000000..029fafc --- /dev/null +++ b/common/mg_str.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MG_STR_H_ +#define CS_COMMON_MG_STR_H_ + +#include + +#include "common/platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Describes chunk of memory */ +struct mg_str { + const char *p; /* Memory chunk pointer */ + size_t len; /* Memory chunk length */ +}; + +/* + * Helper functions for creating mg_str struct from plain C string. + * `NULL` is allowed and becomes `{NULL, 0}`. + */ +struct mg_str mg_mk_str(const char *s); +struct mg_str mg_mk_str_n(const char *s, size_t len); + +/* Macro for initializing mg_str. */ +#define MG_MK_STR(str_literal) \ + { str_literal, sizeof(str_literal) - 1 } +#define MG_NULL_STR \ + { NULL, 0 } + +/* + * Cross-platform version of `strcmp()` where where first string is + * specified by `struct mg_str`. + */ +int mg_vcmp(const struct mg_str *str2, const char *str1); + +/* + * Cross-platform version of `strncasecmp()` where first string is + * specified by `struct mg_str`. + */ +int mg_vcasecmp(const struct mg_str *str2, const char *str1); + +/* Creates a copy of s (heap-allocated). */ +struct mg_str mg_strdup(const struct mg_str s); + +/* + * Creates a copy of s (heap-allocated). + * Resulting string is NUL-terminated (but NUL is not included in len). + */ +struct mg_str mg_strdup_nul(const struct mg_str s); + +/* + * Locates character in a string. + */ +const char *mg_strchr(const struct mg_str s, int c); + +int mg_strcmp(const struct mg_str str1, const struct mg_str str2); +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); + +const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); + +#ifdef __cplusplus +} +#endif + +#endif /* CS_COMMON_MG_STR_H_ */ From 3c9e9dcf25ef6c6f38596ae1640aed7dc5cb0b04 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 18 Aug 2017 00:44:30 +0100 Subject: [PATCH 071/265] Remove cesanta.com/be/... from GO_PACKAGES PUBLISHED_FROM=ce48c879bb4aeb15f8a16f8df5311585b7f3931d --- common.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/common.mk b/common.mk index 75d43dc..609770b 100644 --- a/common.mk +++ b/common.mk @@ -1,5 +1,4 @@ GO_PACKAGES = $(shell go list cesanta.com/cloud/... | grep -v vendor) \ - cesanta.com/be/... \ cesanta.com/clubby/... \ cesanta.com/common/... \ cesanta.com/fw/... \ From e16734140dd47d4384ec180edf1d029d4d73d335 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 18 Aug 2017 00:48:06 +0100 Subject: [PATCH 072/265] Check if provided mJS callback is a function PUBLISHED_FROM=cad12c08a94c64cafe65e195b7707c58a829a433 --- mjs.c | 22 +++++++++++++++------- mjs/src/mjs_ffi.c | 22 +++++++++++++++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/mjs.c b/mjs.c index b107137..5de9d4a 100644 --- a/mjs.c +++ b/mjs.c @@ -9546,13 +9546,21 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } break; case MJS_FFI_CTYPE_CALLBACK: - /* - * Current argument is a callback function pointer: remember the given - * JS - * function and the argument index - */ - cbdata.func = arg; - cbdata.func_idx = i; + if (mjs_is_function(arg) || mjs_is_foreign(arg) || + mjs_is_ffi_sig(arg)) { + /* + * Current argument is a callback function pointer: remember the given + * JS function and the argument index + */ + cbdata.func = arg; + cbdata.func_idx = i; + } else { + ret = MJS_TYPE_ERROR; + mjs_prepend_errorf(mjs, ret, + "actual arg #%d is not a function, but %s", i, + mjs_stringify_type(arg)); + goto clean; + } break; case MJS_FFI_CTYPE_INVALID: /* parse_cval_type() has already set a more detailed error */ diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index c5dadd1..919960f 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -766,13 +766,21 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } break; case MJS_FFI_CTYPE_CALLBACK: - /* - * Current argument is a callback function pointer: remember the given - * JS - * function and the argument index - */ - cbdata.func = arg; - cbdata.func_idx = i; + if (mjs_is_function(arg) || mjs_is_foreign(arg) || + mjs_is_ffi_sig(arg)) { + /* + * Current argument is a callback function pointer: remember the given + * JS function and the argument index + */ + cbdata.func = arg; + cbdata.func_idx = i; + } else { + ret = MJS_TYPE_ERROR; + mjs_prepend_errorf(mjs, ret, + "actual arg #%d is not a function, but %s", i, + mjs_stringify_type(arg)); + goto clean; + } break; case MJS_FFI_CTYPE_INVALID: /* parse_cval_type() has already set a more detailed error */ From 9e0c7223f197fa5c3ef4c0a7d59616dde0d35d4d Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 20 Aug 2017 23:47:19 +0100 Subject: [PATCH 073/265] Fix zero-length foreign strings Zero length for the foreign string means that the string is not inlined into mjs_val_t. Resolves https://github.com/cesanta/dev/issues/8445 PUBLISHED_FROM=18947c953476af908e6f3d3463df9f8b73b6b4c2 --- mjs.c | 9 +++++++++ mjs/src/mjs_string.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/mjs.c b/mjs.c index 5de9d4a..c7a8cf9 100644 --- a/mjs.c +++ b/mjs.c @@ -12412,6 +12412,15 @@ int mjs_is_string(mjs_val_t v) { } mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { + if (len == 0) { + /* + * Zero length for foreign string has a special meaning (that the foreign + * string is not inlined into mjs_val_t), so when creating a zero-length + * string, we always assume it'll be owned. Since the length is zero, it + * doesn't matter anyway. + */ + copy = 1; + } struct mbuf *m = copy ? &mjs->owned_strings : &mjs->foreign_strings; mjs_val_t offset = m->len, tag = MJS_TAG_STRING_F; diff --git a/mjs/src/mjs_string.c b/mjs/src/mjs_string.c index a94e518..b31c4a9 100644 --- a/mjs/src/mjs_string.c +++ b/mjs/src/mjs_string.c @@ -41,6 +41,15 @@ int mjs_is_string(mjs_val_t v) { } mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { + if (len == 0) { + /* + * Zero length for foreign string has a special meaning (that the foreign + * string is not inlined into mjs_val_t), so when creating a zero-length + * string, we always assume it'll be owned. Since the length is zero, it + * doesn't matter anyway. + */ + copy = 1; + } struct mbuf *m = copy ? &mjs->owned_strings : &mjs->foreign_strings; mjs_val_t offset = m->len, tag = MJS_TAG_STRING_F; From 90da1033b100a9b0d9937008b77bc427777d5a09 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 21 Aug 2017 08:47:37 +0100 Subject: [PATCH 074/265] CC3220 blinky Ignore all the mess, this is just the beginning... PUBLISHED_FROM=41ab3c5af0b1d07204619dd4d8dc2e84b6a54f32 --- common/platform.h | 8 +- common/platforms/cc3200/ti.mk | 1 - common/platforms/platform_cc3200.h | 4 +- common/platforms/platform_cc3220.h | 106 +++++++++++++ common/platforms/simplelink/cs_simplelink.h | 6 + mjs.c | 167 +++++++++++++++++--- 6 files changed, 263 insertions(+), 29 deletions(-) create mode 100644 common/platforms/platform_cc3220.h diff --git a/common/platform.h b/common/platform.h index e3075a7..ad86a0a 100644 --- a/common/platform.h +++ b/common/platform.h @@ -10,9 +10,10 @@ #define CS_P_WINDOWS 2 #define CS_P_ESP32 15 #define CS_P_ESP8266 3 +#define CS_P_CC3100 6 #define CS_P_CC3200 4 +#define CS_P_CC3220 17 #define CS_P_MSP432 5 -#define CS_P_CC3100 6 #define CS_P_TM4C129 14 #define CS_P_MBED 7 #define CS_P_WINCE 8 @@ -22,7 +23,7 @@ #define CS_P_NRF52 10 #define CS_P_PIC32 11 #define CS_P_STM32 16 -/* Next id: 17 */ +/* Next id: 18 */ /* If not specified explicitly, we guess platform by defines. */ #ifndef CS_PLATFORM @@ -75,8 +76,9 @@ #include "common/platforms/platform_windows.h" #include "common/platforms/platform_esp32.h" #include "common/platforms/platform_esp8266.h" -#include "common/platforms/platform_cc3200.h" #include "common/platforms/platform_cc3100.h" +#include "common/platforms/platform_cc3200.h" +#include "common/platforms/platform_cc3220.h" #include "common/platforms/platform_mbed.h" #include "common/platforms/platform_nrf51.h" #include "common/platforms/platform_nrf52.h" diff --git a/common/platforms/cc3200/ti.mk b/common/platforms/cc3200/ti.mk index 611800f..a55b1d8 100644 --- a/common/platforms/cc3200/ti.mk +++ b/common/platforms/cc3200/ti.mk @@ -45,7 +45,6 @@ define link --generate_dead_funcs_list=$@.garbage.xml \ -i $(TOOLCHAIN)/lib \ --reread_libs --warn_sections --display_error_number \ - --ram_model --cinit_compression=off --copy_compression=off \ --unused_section_elimination=on \ -o $@ --map_file=$@.map --xml_link_info=$@.map.xml \ $2 $1 $3 diff --git a/common/platforms/platform_cc3200.h b/common/platforms/platform_cc3200.h index b7ec878..af5580e 100644 --- a/common/platforms/platform_cc3200.h +++ b/common/platforms/platform_cc3200.h @@ -92,8 +92,10 @@ int stat(const char *pathname, struct stat *st); #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) -/* As of 5.2.7, TI compiler does not support va_copy() yet. */ +/* 5.x series compilers don't have va_copy, 16.x do. */ +#if __TI_COMPILER_VERSION__ < 16000000 #define va_copy(apc, ap) ((apc) = (ap)) +#endif #endif /* __TI_COMPILER_VERSION__ */ diff --git a/common/platforms/platform_cc3220.h b/common/platforms/platform_cc3220.h new file mode 100644 index 0000000..95ed4cf --- /dev/null +++ b/common/platforms/platform_cc3220.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#if CS_PLATFORM == CS_P_CC3220 + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK + +/* Only SPIFFS supports directories, SLFS does not. */ +#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING) +#define MG_ENABLE_DIRECTORY_LISTING 1 +#endif + +#include "common/platforms/simplelink/cs_simplelink.h" + +typedef int sock_t; +#define INVALID_SOCKET (-1) +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define DIRSEP '/' +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define __cdecl + +#define fileno(x) -1 + +/* Some functions we implement for Mongoose. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __TI_COMPILER_VERSION__ +struct SlTimeval_t; +#define timeval SlTimeval_t +int gettimeofday(struct timeval *t, void *tz); +int settimeofday(const struct timeval *tv, const void *tz); + +int asprintf(char **strp, const char *fmt, ...); + +#endif + +/* TI's libc does not have stat & friends, add them. */ +#ifdef __TI_COMPILER_VERSION__ + +#include + +typedef unsigned int mode_t; +typedef size_t _off_t; +typedef long ssize_t; + +struct stat { + int st_ino; + mode_t st_mode; + int st_nlink; + time_t st_mtime; + off_t st_size; +}; + +int _stat(const char *pathname, struct stat *st); +int stat(const char *pathname, struct stat *st); + +#define __S_IFMT 0170000 + +#define __S_IFDIR 0040000 +#define __S_IFCHR 0020000 +#define __S_IFREG 0100000 + +#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask)) + +#define S_IFDIR __S_IFDIR +#define S_IFCHR __S_IFCHR +#define S_IFREG __S_IFREG +#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) +#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) + +#endif /* __TI_COMPILER_VERSION__ */ + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_CC3220 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index 3c503e0..a81351c 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -22,6 +22,11 @@ #undef fd_set #endif +#if CS_PLATFORM == CS_P_CC3220 +#include +#include +#include +#else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves * and undef it. */ #define PROVISIONING_API_H_ @@ -31,6 +36,7 @@ #include #include +#endif /* CS_PLATFORM == CS_P_CC3220 */ /* Now define only the subset of the BSD API that we use. * Notably, close(), read() and write() are not defined. */ diff --git a/mjs.c b/mjs.c index c7a8cf9..2087ec0 100644 --- a/mjs.c +++ b/mjs.c @@ -14,9 +14,10 @@ #define CS_P_WINDOWS 2 #define CS_P_ESP32 15 #define CS_P_ESP8266 3 +#define CS_P_CC3100 6 #define CS_P_CC3200 4 +#define CS_P_CC3220 17 #define CS_P_MSP432 5 -#define CS_P_CC3100 6 #define CS_P_TM4C129 14 #define CS_P_MBED 7 #define CS_P_WINCE 8 @@ -26,7 +27,7 @@ #define CS_P_NRF52 10 #define CS_P_PIC32 11 #define CS_P_STM32 16 -/* Next id: 17 */ +/* Next id: 18 */ /* If not specified explicitly, we guess platform by defines. */ #ifndef CS_PLATFORM @@ -79,8 +80,9 @@ /* Amalgamated: #include "common/platforms/platform_windows.h" */ /* Amalgamated: #include "common/platforms/platform_esp32.h" */ /* Amalgamated: #include "common/platforms/platform_esp8266.h" */ -/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ /* Amalgamated: #include "common/platforms/platform_cc3100.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3220.h" */ /* Amalgamated: #include "common/platforms/platform_mbed.h" */ /* Amalgamated: #include "common/platforms/platform_nrf51.h" */ /* Amalgamated: #include "common/platforms/platform_nrf52.h" */ @@ -542,6 +544,55 @@ typedef struct stat cs_stat_t; #endif /* CS_PLATFORM == CS_P_ESP8266 */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */ #ifdef MJS_MODULE_LINES +#line 1 "common/platforms/platform_cc3100.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ +#if CS_PLATFORM == CS_P_CC3100 + +#include +#include +#include +#include +#include +#include +#include + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK + +/* + * CC3100 SDK and STM32 SDK include headers w/out path, just like + * #include "simplelink.h". As result, we have to add all required directories + * into Makefile IPATH and do the same thing (include w/out path) + */ + +#include +#include +#undef timeval + +typedef int sock_t; +#define INVALID_SOCKET (-1) + +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define SIZE_T_FMT "u" + +#define SOMAXCONN 8 + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +char *inet_ntoa(struct in_addr in); +int inet_pton(int af, const char *src, void *dst); + +#endif /* CS_PLATFORM == CS_P_CC3100 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */ +#ifdef MJS_MODULE_LINES #line 1 "common/platforms/simplelink/cs_simplelink.h" #endif /* @@ -568,6 +619,11 @@ typedef struct stat cs_stat_t; #undef fd_set #endif +#if CS_PLATFORM == CS_P_CC3220 +#include +#include +#include +#else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves * and undef it. */ #define PROVISIONING_API_H_ @@ -577,6 +633,7 @@ typedef struct stat cs_stat_t; #include #include +#endif /* CS_PLATFORM == CS_P_CC3220 */ /* Now define only the subset of the BSD API that we use. * Notably, close(), read() and write() are not defined. */ @@ -745,8 +802,10 @@ int stat(const char *pathname, struct stat *st); #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) -/* As of 5.2.7, TI compiler does not support va_copy() yet. */ +/* 5.x series compilers don't have va_copy, 16.x do. */ +#if __TI_COMPILER_VERSION__ < 16000000 #define va_copy(apc, ap) ((apc) = (ap)) +#endif #endif /* __TI_COMPILER_VERSION__ */ @@ -771,16 +830,16 @@ int stat(const char *pathname, struct stat *st); #endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ #ifdef MJS_MODULE_LINES -#line 1 "common/platforms/platform_cc3100.h" +#line 1 "common/platforms/platform_cc3220.h" #endif /* * Copyright (c) 2014-2016 Cesanta Software Limited * All rights reserved */ -#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ -#if CS_PLATFORM == CS_P_CC3100 +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#if CS_PLATFORM == CS_P_CC3220 #include #include @@ -790,35 +849,95 @@ int stat(const char *pathname, struct stat *st); #include #include +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + #define MG_NET_IF MG_NET_IF_SIMPLELINK #define MG_SSL_IF MG_SSL_IF_SIMPLELINK -/* - * CC3100 SDK and STM32 SDK include headers w/out path, just like - * #include "simplelink.h". As result, we have to add all required directories - * into Makefile IPATH and do the same thing (include w/out path) - */ +/* Only SPIFFS supports directories, SLFS does not. */ +#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING) +#define MG_ENABLE_DIRECTORY_LISTING 1 +#endif -#include -#include -#undef timeval +/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */ typedef int sock_t; #define INVALID_SOCKET (-1) - +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define DIRSEP '/' #define to64(x) strtoll(x, NULL, 10) #define INT64_FMT PRId64 #define INT64_X_FMT PRIx64 -#define SIZE_T_FMT "u" +#define __cdecl -#define SOMAXCONN 8 +#define fileno(x) -1 -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); -char *inet_ntoa(struct in_addr in); -int inet_pton(int af, const char *src, void *dst); +/* Some functions we implement for Mongoose. */ -#endif /* CS_PLATFORM == CS_P_CC3100 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __TI_COMPILER_VERSION__ +struct SlTimeval_t; +#define timeval SlTimeval_t +int gettimeofday(struct timeval *t, void *tz); +int settimeofday(const struct timeval *tv, const void *tz); + +int asprintf(char **strp, const char *fmt, ...); + +#endif + +/* TI's libc does not have stat & friends, add them. */ +#ifdef __TI_COMPILER_VERSION__ + +#include + +typedef unsigned int mode_t; +typedef size_t _off_t; +typedef long ssize_t; + +struct stat { + int st_ino; + mode_t st_mode; + int st_nlink; + time_t st_mtime; + off_t st_size; +}; + +int _stat(const char *pathname, struct stat *st); +int stat(const char *pathname, struct stat *st); + +#define __S_IFMT 0170000 + +#define __S_IFDIR 0040000 +#define __S_IFCHR 0020000 +#define __S_IFREG 0100000 + +#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask)) + +#define S_IFDIR __S_IFDIR +#define S_IFCHR __S_IFCHR +#define S_IFREG __S_IFREG +#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) +#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) + +#endif /* __TI_COMPILER_VERSION__ */ + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_CC3220 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ #ifdef MJS_MODULE_LINES #line 1 "common/platforms/platform_mbed.h" #endif From 4d893608d41b5d5ba27f784ea798a0480686c965 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 21 Aug 2017 15:07:24 +0100 Subject: [PATCH 075/265] Enable LWIP net_if locking on ESP32 (doh!) https://forum.mongoose-os.com/discussion/comment/4620/#Comment_4620 PUBLISHED_FROM=679dd48e078615ef4f57d1879957b734f549ef2e --- common/platforms/lwip/mg_lwip_net_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index a6b93e3..59e2e52 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -67,7 +67,7 @@ void mg_lwip_if_add_conn(struct mg_connection *nc); void mg_lwip_if_remove_conn(struct mg_connection *nc); time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms); -#ifdef RTOS_SDK +#if defined(RTOS_SDK) || defined(ESP_PLATFORM) extern void mgos_lock(); extern void mgos_unlock(); #else From 0a18a0308754c99e12b40428905732a6b35701e3 Mon Sep 17 00:00:00 2001 From: Our CI Bot Date: Sat, 26 Aug 2017 00:39:37 +0300 Subject: [PATCH 076/265] Add File.rename() PUBLISHED_FROM=a81dd9f7a259716a4a5edc576e13cc6054875b1d --- mjs/lib/api_file.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mjs/lib/api_file.js b/mjs/lib/api_file.js index 42b91ac..ea01b8d 100644 --- a/mjs/lib/api_file.js +++ b/mjs/lib/api_file.js @@ -25,6 +25,10 @@ let File = { // on success, non-0 on failure. remove: ffi('int remove(char *)'), + // **`File.rename(old, new)`** + // Rename file `old` to `new`. Return 0 on success, non-0 on failure. + rename: ffi('int rename(char *, char *)'), + // **`File.write(str, name, mode)`** // Write string `str` into file `name`. // From df4188a4e18966c44cfb8635bd7f190eee9231f1 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 26 Aug 2017 18:02:08 +0100 Subject: [PATCH 077/265] CC3220 first steps Achievement unlocked: CC3220 port prints a boot banner. Then locks up. Included in this PR is refactoring to pull out common parts to be shared with CC3200. PUBLISHED_FROM=5fb9d9a00bb9ce7f63dde20bc1876076b76d5257 --- common/platform.h | 4 ++- common/platforms/simplelink/cs_simplelink.h | 23 +++++++++++++-- common/platforms/simplelink/sl_net_if.c | 31 ++++++++++++--------- common/platforms/simplelink/sl_socket.c | 4 +-- common/platforms/simplelink/sl_ssl_if.c | 7 +++-- mjs.c | 27 +++++++++++++++--- 6 files changed, 70 insertions(+), 26 deletions(-) diff --git a/common/platform.h b/common/platform.h index ad86a0a..b517cab 100644 --- a/common/platform.h +++ b/common/platform.h @@ -30,8 +30,10 @@ #if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) #define CS_PLATFORM CS_P_MSP432 -#elif defined(cc3200) +#elif defined(cc3200) || defined(TARGET_IS_CC3200) #define CS_PLATFORM CS_P_CC3200 +#elif defined(cc3220) || defined(TARGET_IS_CC3220) +#define CS_PLATFORM CS_P_CC3220 #elif defined(__unix__) || defined(__APPLE__) #define CS_PLATFORM CS_P_UNIX #elif defined(WINCE) diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index a81351c..b6ca01a 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -6,9 +6,10 @@ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ #define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ +#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK + /* If simplelink.h is already included, all bets are off. */ -#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK && \ - !defined(__SIMPLELINK_H__) +#if !defined(__SIMPLELINK_H__) #include @@ -25,6 +26,7 @@ #if CS_PLATFORM == CS_P_CC3220 #include #include +#include #include #else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves @@ -105,6 +107,21 @@ int sl_set_ssl_opts(struct mg_connection *nc); } #endif -#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(__SIMPLELINK_H__) */ +#endif /* !defined(__SIMPLELINK_H__) */ + +/* COmpatibility with older versions of SimpleLink */ +#if SL_MAJOR_VERSION_NUM < 2 +#define SL_ERROR_BSD_EAGAIN SL_EAGAIN +#define SL_ERROR_BSD_EALREADY SL_EALREADY +#define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT +#define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR +#define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_SOCKET_FD_ZERO SL_FD_ZERO +#define SL_SOCKET_FD_SET SL_FD_SET +#define SL_SOCKET_FD_ISSET SL_FD_ISSET +#define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#endif + +#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */ diff --git a/common/platforms/simplelink/sl_net_if.c b/common/platforms/simplelink/sl_net_if.c index 76985cf..ab4894b 100644 --- a/common/platforms/simplelink/sl_net_if.c +++ b/common/platforms/simplelink/sl_net_if.c @@ -20,12 +20,16 @@ int sl_set_ssl_opts(struct mg_connection *nc); void mg_set_non_blocking_mode(sock_t sock) { SlSockNonblocking_t opt; +#if SL_MAJOR_VERSION_NUM < 2 opt.NonblockingEnabled = 1; +#else + opt.NonBlockingEnabled = 1; +#endif sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt)); } static int mg_is_error(int n) { - return (n < 0 && n != SL_EALREADY && n != SL_EAGAIN); + return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN); } void mg_sl_if_connect_tcp(struct mg_connection *nc, @@ -226,7 +230,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); if (nc->flags & MG_F_CONNECTING) { - if (nc->flags & MG_F_UDP || nc->err != SL_EALREADY) { + if (nc->flags & MG_F_UDP || nc->err != SL_ERROR_BSD_EALREADY) { mg_if_connect_cb(nc, nc->err); } else { /* In SimpleLink, to get status of non-blocking connect() we need to wait @@ -235,9 +239,9 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_WRITE) { nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin)); DBG(("%p conn res=%d", nc, nc->err)); - if (nc->err == SL_ESECSNOVERIFY || + if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY || /* TODO(rojer): Provide API to set the date for verification. */ - nc->err == SL_ESECDATEERROR) { + nc->err == SL_ERROR_BSD_ESECDATEERROR) { nc->err = 0; } if (nc->flags & MG_F_SSL && nc->err == 0) { @@ -311,9 +315,9 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { sock_t max_fd = INVALID_SOCKET; int num_fds, num_ev = 0, num_timers = 0; - SL_FD_ZERO(&read_set); - SL_FD_ZERO(&write_set); - SL_FD_ZERO(&err_set); + SL_SOCKET_FD_ZERO(&read_set); + SL_SOCKET_FD_ZERO(&write_set); + SL_SOCKET_FD_ZERO(&err_set); /* * Note: it is ok to have connections with sock == INVALID_SOCKET in the list, @@ -329,14 +333,14 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { if (!(nc->flags & MG_F_WANT_WRITE) && nc->recv_mbuf.len < nc->recv_mbuf_limit && (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) { - SL_FD_SET(nc->sock, &read_set); + SL_SOCKET_FD_SET(nc->sock, &read_set); if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock; } if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) || (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) { - SL_FD_SET(nc->sock, &write_set); - SL_FD_SET(nc->sock, &err_set); + SL_SOCKET_FD_SET(nc->sock, &write_set); + SL_SOCKET_FD_SET(nc->sock, &err_set); if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock; } } @@ -377,12 +381,13 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { if (nc->sock != INVALID_SOCKET) { if (num_ev > 0) { fd_flags = - (SL_FD_ISSET(nc->sock, &read_set) && + (SL_SOCKET_FD_ISSET(nc->sock, &read_set) && (!(nc->flags & MG_F_UDP) || nc->listener == NULL) ? _MG_F_FD_CAN_READ : 0) | - (SL_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) | - (SL_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0); + (SL_SOCKET_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE + : 0) | + (SL_SOCKET_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0); } /* SimpleLink does not report UDP sockets as writable. */ if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) { diff --git a/common/platforms/simplelink/sl_socket.c b/common/platforms/simplelink/sl_socket.c index 561f1ab..e4a0c26 100644 --- a/common/platforms/simplelink/sl_socket.c +++ b/common/platforms/simplelink/sl_socket.c @@ -14,7 +14,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { int res; struct in_addr *in = (struct in_addr *) src; if (af != AF_INET) { - errno = EAFNOSUPPORT; + errno = ENOTSUP; return NULL; } res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0), @@ -32,7 +32,7 @@ int inet_pton(int af, const char *src, void *dst) { uint32_t a0, a1, a2, a3; uint8_t *db = (uint8_t *) dst; if (af != AF_INET) { - errno = EAFNOSUPPORT; + errno = ENOTSUP; return 0; } if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) { diff --git a/common/platforms/simplelink/sl_ssl_if.c b/common/platforms/simplelink/sl_ssl_if.c index 95c801d..4945880 100644 --- a/common/platforms/simplelink/sl_ssl_if.c +++ b/common/platforms/simplelink/sl_ssl_if.c @@ -195,13 +195,14 @@ int sl_set_ssl_opts(struct mg_connection *nc) { } if (ctx->ssl_server_name != NULL) { err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, - SO_SECURE_DOMAIN_NAME_VERIFICATION, + SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, ctx->ssl_server_name, strlen(ctx->ssl_server_name)); DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); /* Domain name verificationw as added in a NWP service pack, older - * versions return SL_ENOPROTOOPT. There isn't much we can do about it, + * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do + * about it, * so we ignore the error. */ - if (err != 0 && err != SL_ENOPROTOOPT) return err; + if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; } } return 0; diff --git a/mjs.c b/mjs.c index 2087ec0..6bd5610 100644 --- a/mjs.c +++ b/mjs.c @@ -34,8 +34,10 @@ #if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) #define CS_PLATFORM CS_P_MSP432 -#elif defined(cc3200) +#elif defined(cc3200) || defined(TARGET_IS_CC3200) #define CS_PLATFORM CS_P_CC3200 +#elif defined(cc3220) || defined(TARGET_IS_CC3220) +#define CS_PLATFORM CS_P_CC3220 #elif defined(__unix__) || defined(__APPLE__) #define CS_PLATFORM CS_P_UNIX #elif defined(WINCE) @@ -603,9 +605,10 @@ int inet_pton(int af, const char *src, void *dst); #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ #define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ +#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK + /* If simplelink.h is already included, all bets are off. */ -#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK && \ - !defined(__SIMPLELINK_H__) +#if !defined(__SIMPLELINK_H__) #include @@ -622,6 +625,7 @@ int inet_pton(int af, const char *src, void *dst); #if CS_PLATFORM == CS_P_CC3220 #include #include +#include #include #else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves @@ -702,7 +706,22 @@ int sl_set_ssl_opts(struct mg_connection *nc); } #endif -#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(__SIMPLELINK_H__) */ +#endif /* !defined(__SIMPLELINK_H__) */ + +/* COmpatibility with older versions of SimpleLink */ +#if SL_MAJOR_VERSION_NUM < 2 +#define SL_ERROR_BSD_EAGAIN SL_EAGAIN +#define SL_ERROR_BSD_EALREADY SL_EALREADY +#define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT +#define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR +#define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_SOCKET_FD_ZERO SL_FD_ZERO +#define SL_SOCKET_FD_SET SL_FD_SET +#define SL_SOCKET_FD_ISSET SL_FD_ISSET +#define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#endif + +#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */ #ifdef MJS_MODULE_LINES From 48363c1cd46f44a01329bfdc851645340bc1f013 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 27 Aug 2017 13:43:17 +0100 Subject: [PATCH 078/265] Add mg_next_comma_list_entry_n() And mgos_conf_check_access_n() PUBLISHED_FROM=c7de937b4f5463ca463d604183a4ee831617bd6d --- common/str_util.c | 27 +++++--- common/str_util.h | 2 + mjs.c | 152 ++++++++++++++++++++++++++++++++++++++--- mjs/src/mjs_sources.mk | 1 + 4 files changed, 166 insertions(+), 16 deletions(-) diff --git a/common/str_util.c b/common/str_util.c index 7758571..92bcddb 100644 --- a/common/str_util.c +++ b/common/str_util.c @@ -409,19 +409,30 @@ const char *mg_next_comma_list_entry(const char *, struct mg_str *, struct mg_str *) WEAK; const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val) { - if (list == NULL || *list == '\0') { + struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val); + return ret.p; +} + +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) WEAK; +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) { + if (list.len == 0) { /* End of the list */ - list = NULL; + list = mg_mk_str(NULL); } else { - val->p = list; - if ((list = strchr(val->p, ',')) != NULL) { + const char *chr = NULL; + *val = list; + + if ((chr = mg_strchr(*val, ',')) != NULL) { /* Comma found. Store length and shift the list ptr */ - val->len = list - val->p; - list++; + val->len = chr - val->p; + chr++; + list.len -= (chr - list.p); + list.p = chr; } else { /* This value is the last one */ - list = val->p + strlen(val->p); - val->len = list - val->p; + list = mg_mk_str_n(list.p + list.len, 0); } if (eq_val != NULL) { diff --git a/common/str_util.h b/common/str_util.h index 888f76d..0745a3c 100644 --- a/common/str_util.h +++ b/common/str_util.h @@ -120,6 +120,8 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); */ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val); +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val); /* * Matches 0-terminated string (mg_match_prefix) or string with given length diff --git a/mjs.c b/mjs.c index 6bd5610..0d37e01 100644 --- a/mjs.c +++ b/mjs.c @@ -1820,6 +1820,8 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); */ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val); +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val); /* * Matches 0-terminated string (mg_match_prefix) or string with given length @@ -4663,6 +4665,129 @@ void mbuf_remove(struct mbuf *mb, size_t n) { #endif /* EXCLUDE_COMMON */ #ifdef MJS_MODULE_LINES +#line 1 "common/mg_str.c" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +/* Amalgamated: #include "common/mg_mem.h" */ +/* Amalgamated: #include "common/mg_str.h" */ + +#include +#include + +int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK; + +struct mg_str mg_mk_str(const char *s) WEAK; +struct mg_str mg_mk_str(const char *s) { + struct mg_str ret = {s, 0}; + if (s != NULL) ret.len = strlen(s); + return ret; +} + +struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK; +struct mg_str mg_mk_str_n(const char *s, size_t len) { + struct mg_str ret = {s, len}; + return ret; +} + +int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcasecmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +static struct mg_str mg_strdup_common(const struct mg_str s, + int nul_terminate) { + struct mg_str r = {NULL, 0}; + if (s.len > 0 && s.p != NULL) { + char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0)); + if (sc != NULL) { + memcpy(sc, s.p, s.len); + if (nul_terminate) sc[s.len] = '\0'; + r.p = sc; + r.len = s.len; + } + } + return r; +} + +struct mg_str mg_strdup(const struct mg_str s) WEAK; +struct mg_str mg_strdup(const struct mg_str s) { + return mg_strdup_common(s, 0 /* NUL-terminate */); +} + +struct mg_str mg_strdup_nul(const struct mg_str s) WEAK; +struct mg_str mg_strdup_nul(const struct mg_str s) { + return mg_strdup_common(s, 1 /* NUL-terminate */); +} + +const char *mg_strchr(const struct mg_str s, int c) WEAK; +const char *mg_strchr(const struct mg_str s, int c) { + size_t i; + for (i = 0; i < s.len; i++) { + if (s.p[i] == c) return &s.p[i]; + } + return NULL; +} + +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { + size_t i = 0; + while (i < str1.len && i < str2.len) { + if (str1.p[i] < str2.p[i]) return -1; + if (str1.p[i] > str2.p[i]) return 1; + i++; + } + if (i < str1.len) return 1; + if (i < str2.len) return -1; + return 0; +} + +int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK; +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { + struct mg_str s1 = str1; + struct mg_str s2 = str2; + + if (s1.len > n) { + s1.len = n; + } + if (s2.len > n) { + s2.len = n; + } + return mg_strcmp(s1, s2); +} + +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) WEAK; +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) { + size_t i; + if (needle.len > haystack.len) return NULL; + for (i = 0; i <= haystack.len - needle.len; i++) { + if (memcmp(haystack.p + i, needle.p, needle.len) == 0) { + return haystack.p + i; + } + } + return NULL; +} +#ifdef MJS_MODULE_LINES #line 1 "common/str_util.c" #endif /* @@ -5076,19 +5201,30 @@ const char *mg_next_comma_list_entry(const char *, struct mg_str *, struct mg_str *) WEAK; const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val) { - if (list == NULL || *list == '\0') { + struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val); + return ret.p; +} + +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) WEAK; +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) { + if (list.len == 0) { /* End of the list */ - list = NULL; + list = mg_mk_str(NULL); } else { - val->p = list; - if ((list = strchr(val->p, ',')) != NULL) { + const char *chr = NULL; + *val = list; + + if ((chr = mg_strchr(*val, ',')) != NULL) { /* Comma found. Store length and shift the list ptr */ - val->len = list - val->p; - list++; + val->len = chr - val->p; + chr++; + list.len -= (chr - list.p); + list.p = chr; } else { /* This value is the last one */ - list = val->p + strlen(val->p); - val->len = list - val->p; + list = mg_mk_str_n(list.p + list.len, 0); } if (eq_val != NULL) { diff --git a/mjs/src/mjs_sources.mk b/mjs/src/mjs_sources.mk index e81881c..f85427d 100644 --- a/mjs/src/mjs_sources.mk +++ b/mjs/src/mjs_sources.mk @@ -5,6 +5,7 @@ SOURCES = $(COMMON)/cs_dbg.c \ $(COMMON)/cs_file.c \ $(COMMON)/cs_varint.c \ $(COMMON)/mbuf.c \ + $(COMMON)/mg_str.c \ $(COMMON)/str_util.c \ $(FROZEN)/frozen.c \ ffi/ffi.c \ From ea600ccd416a74fdf067ad252cd5e75f40bedd77 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 00:44:29 +0300 Subject: [PATCH 079/265] CC3220: Exception handling, NWP init Also make CC3200 use newer ARM compiler, generates slightly smaller code. PUBLISHED_FROM=a0be49d7ea864a95886f7110887a59f6f11802d7 --- common/platforms/cc3200/cc3200_libc.c | 22 --------------------- common/platforms/simplelink/cs_simplelink.h | 9 ++++++++- mjs.c | 9 ++++++++- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/common/platforms/cc3200/cc3200_libc.c b/common/platforms/cc3200/cc3200_libc.c index bd5ef4f..f488725 100644 --- a/common/platforms/cc3200/cc3200_libc.c +++ b/common/platforms/cc3200/cc3200_libc.c @@ -62,28 +62,6 @@ time_t HOSTtime() { #endif /* __TI_COMPILER_VERSION__ */ -#ifndef __TI_COMPILER_VERSION__ -int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tz) { -#else -int gettimeofday(struct timeval *tp, void *tz) { -#endif - unsigned long sec; - unsigned short msec; - MAP_PRCMRTCGet(&sec, &msec); - tp->tv_sec = sec; - tp->tv_usec = ((unsigned long) msec) * 1000; - return 0; -} - -#ifndef __TI_COMPILER_VERSION__ -int settimeofday(const struct timeval *tv, const struct timezone *tz) { -#else -int settimeofday(const struct timeval *tv, const void *tz) { -#endif - MAP_PRCMRTCSet(tv->tv_sec, tv->tv_usec / 1000); - return 0; -} - void fprint_str(FILE *fp, const char *str) { while (*str != '\0') { if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r'); diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index b6ca01a..e224366 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -109,7 +109,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #endif /* !defined(__SIMPLELINK_H__) */ -/* COmpatibility with older versions of SimpleLink */ +/* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY @@ -120,6 +120,13 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION + +#define SlDeviceVersion_t SlVersionFull +#define sl_DeviceGet sl_DevGet +#define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION +#define SL_DEV_GET_LEN_TYPE _u8 +#else +#define SL_DEV_GET_LEN_TYPE _u16 #endif #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ diff --git a/mjs.c b/mjs.c index 0d37e01..341b72d 100644 --- a/mjs.c +++ b/mjs.c @@ -708,7 +708,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #endif /* !defined(__SIMPLELINK_H__) */ -/* COmpatibility with older versions of SimpleLink */ +/* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY @@ -719,6 +719,13 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION + +#define SlDeviceVersion_t SlVersionFull +#define sl_DeviceGet sl_DevGet +#define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION +#define SL_DEV_GET_LEN_TYPE _u8 +#else +#define SL_DEV_GET_LEN_TYPE _u16 #endif #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ From 224f828c299b6823aa73bb02d542f58875817114 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 17:44:36 +0100 Subject: [PATCH 080/265] CC3220 FS support For now, we only support SPIFFS-in-a-box, same as CC3200. On CC3200SF it should be possible to have SPIFFS on built-in flash, but that is left for later. PUBLISHED_FROM=dee337c8cd8ed288c22abe9960eef81e6e90cc4a --- common/platforms/simplelink/cs_simplelink.h | 31 ++++++++++++- common/platforms/simplelink/sl_fs_slfs.c | 48 +++++++++++++-------- mjs.c | 31 ++++++++++++- 3 files changed, 87 insertions(+), 23 deletions(-) diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index e224366..684c518 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -111,23 +111,50 @@ int sl_set_ssl_opts(struct mg_connection *nc); /* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 + #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY #define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT #define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR #define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM SL_FS_ERR_FAILED_TO_ALLOCATE_MEM +#define SL_ERROR_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY \ + SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY +#define SL_ERROR_FS_FILE_NAME_EXIST SL_FS_FILE_NAME_EXIST +#define SL_ERROR_FS_FILE_NOT_EXISTS SL_FS_ERR_FILE_NOT_EXISTS +#define SL_ERROR_FS_NO_AVAILABLE_NV_INDEX SL_FS_ERR_NO_AVAILABLE_NV_INDEX +#define SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE SL_FS_ERR_NO_AVAILABLE_BLOCKS +#define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED +#define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME +#define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#define SL_FS_READ FS_MODE_OPEN_READ +#define SL_FS_WRITE FS_MODE_OPEN_WRITE + +#define SL_FI_FILE_SIZE(fi) ((fi).FileLen) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).AllocatedLen) + #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION #define SL_DEV_GET_LEN_TYPE _u8 -#else + +#else /* SL_MAJOR_VERSION_NUM >= 2 */ + +#define FS_MODE_OPEN_CREATE(max_size, flag) \ + (SL_FS_CREATE | SL_FS_CREATE_MAX_SIZE(max_size)) +#define SL_FI_FILE_SIZE(fi) ((fi).Len) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) + #define SL_DEV_GET_LEN_TYPE _u16 -#endif + +#endif /* SL_MAJOR_VERSION_NUM < 2 */ + +int slfs_open(const unsigned char *fname, uint32_t flags); #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ diff --git a/common/platforms/simplelink/sl_fs_slfs.c b/common/platforms/simplelink/sl_fs_slfs.c index b338887..2754b6b 100644 --- a/common/platforms/simplelink/sl_fs_slfs.c +++ b/common/platforms/simplelink/sl_fs_slfs.c @@ -14,12 +14,22 @@ #if CS_PLATFORM == CS_P_CC3200 #include #endif -#include -#include #include "common/cs_dbg.h" #include "common/mg_mem.h" +#if SL_MAJOR_VERSION_NUM < 2 +int slfs_open(const unsigned char *fname, uint32_t flags) { + _i32 fh; + _i32 r = sl_FsOpen(fname, flags, NULL /* token */, &fh); + return (r < 0 ? r : fh); +} +#else /* SL_MAJOR_VERSION_NUM >= 2 */ +int slfs_open(const unsigned char *fname, uint32_t flags) { + return sl_FsOpen(fname, flags, NULL /* token */); +} +#endif + /* From sl_fs.c */ int set_errno(int e); const char *drop_dir(const char *fname, bool *is_slfs); @@ -51,18 +61,18 @@ static int sl_fs_to_errno(_i32 r) { switch (r) { case SL_FS_OK: return 0; - case SL_FS_FILE_NAME_EXIST: + case SL_ERROR_FS_FILE_NAME_EXIST: return EEXIST; - case SL_FS_WRONG_FILE_NAME: + case SL_ERROR_FS_WRONG_FILE_NAME: return EINVAL; - case SL_FS_ERR_NO_AVAILABLE_NV_INDEX: - case SL_FS_ERR_NO_AVAILABLE_BLOCKS: + case SL_ERROR_FS_NO_AVAILABLE_NV_INDEX: + case SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE: return ENOSPC; - case SL_FS_ERR_FAILED_TO_ALLOCATE_MEM: + case SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM: return ENOMEM; - case SL_FS_ERR_FILE_NOT_EXISTS: + case SL_ERROR_FS_FILE_NOT_EXISTS: return ENOENT; - case SL_FS_ERR_NOT_SUPPORTED: + case SL_ERROR_FS_NOT_SUPPORTED: return ENOTSUP; } return ENXIO; @@ -90,9 +100,9 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { SlFsFileInfo_t sl_fi; _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); if (r == SL_FS_OK) { - fi->size = sl_fi.FileLen; + fi->size = SL_FI_FILE_SIZE(sl_fi); } - am = FS_MODE_OPEN_READ; + am = SL_FS_READ; } else { if (!(flags & O_TRUNC) || (flags & O_APPEND)) { // FailFS files cannot be opened for append and will be truncated @@ -112,18 +122,18 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { } am = FS_MODE_OPEN_CREATE(new_size, 0); } else { - am = FS_MODE_OPEN_WRITE; + am = SL_FS_WRITE; } } - _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh); - LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d, %d", pathname, (int) am, - (unsigned int) new_size, (int) r, (int) fi->fh)); - if (r == SL_FS_OK) { + fi->fh = slfs_open((_u8 *) pathname, am); + LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d", pathname, (int) am, + (unsigned int) new_size, (int) fi->fh)); + int r; + if (fi->fh >= 0) { fi->pos = 0; r = fd; } else { - fi->fh = -1; - r = set_errno(sl_fs_to_errno(r)); + r = set_errno(sl_fs_to_errno(fi->fh)); } return r; } @@ -177,7 +187,7 @@ int fs_slfs_stat(const char *pathname, struct stat *s) { if (r == SL_FS_OK) { s->st_mode = S_IFREG | 0666; s->st_nlink = 1; - s->st_size = sl_fi.FileLen; + s->st_size = SL_FI_FILE_SIZE(sl_fi); return 0; } return set_errno(sl_fs_to_errno(r)); diff --git a/mjs.c b/mjs.c index 341b72d..12b9985 100644 --- a/mjs.c +++ b/mjs.c @@ -710,23 +710,50 @@ int sl_set_ssl_opts(struct mg_connection *nc); /* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 + #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY #define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT #define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR #define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM SL_FS_ERR_FAILED_TO_ALLOCATE_MEM +#define SL_ERROR_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY \ + SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY +#define SL_ERROR_FS_FILE_NAME_EXIST SL_FS_FILE_NAME_EXIST +#define SL_ERROR_FS_FILE_NOT_EXISTS SL_FS_ERR_FILE_NOT_EXISTS +#define SL_ERROR_FS_NO_AVAILABLE_NV_INDEX SL_FS_ERR_NO_AVAILABLE_NV_INDEX +#define SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE SL_FS_ERR_NO_AVAILABLE_BLOCKS +#define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED +#define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME +#define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#define SL_FS_READ FS_MODE_OPEN_READ +#define SL_FS_WRITE FS_MODE_OPEN_WRITE + +#define SL_FI_FILE_SIZE(fi) ((fi).FileLen) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).AllocatedLen) + #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION #define SL_DEV_GET_LEN_TYPE _u8 -#else + +#else /* SL_MAJOR_VERSION_NUM >= 2 */ + +#define FS_MODE_OPEN_CREATE(max_size, flag) \ + (SL_FS_CREATE | SL_FS_CREATE_MAX_SIZE(max_size)) +#define SL_FI_FILE_SIZE(fi) ((fi).Len) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) + #define SL_DEV_GET_LEN_TYPE _u16 -#endif + +#endif /* SL_MAJOR_VERSION_NUM < 2 */ + +int slfs_open(const unsigned char *fname, uint32_t flags); #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ From 2e0bac54c0d56afd8029f000a48c142604d56359 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 18:38:24 +0100 Subject: [PATCH 081/265] CC3220: GPIO, sys_config and mgos_init support ``` Using port /dev/ttyACM0 [Aug 30 19:33:02.105] [Aug 30 19:33:02.114] cc32xx_init c_no_libs 1.0 (20170830-163205/mos8@6587ffd6+) [Aug 30 19:33:02.123] cc32xx_init Mongoose OS 2017083016 (20170830-163205/mos8@6587ffd6+) [Aug 30 19:33:02.130] cc32xx_init RAM: 253588 total, 240044 free [Aug 30 19:33:04.430] cc32xx_start_nwp NWP v3.4.0.0 started, host driver v2.0.1.19 [Aug 30 19:33:04.437] mgos_vfs_dev_open slfs_container ({"prefix": "spiffs.img.0"}) -> 20005a64 [Aug 30 19:33:04.450] cc32xx_vfs_dev_slfs_ 20005a64 spiffs.img.0.0 262144 0xfffffffffffffffe [Aug 30 19:33:04.457] mgos_vfs_mount Mount SPIFFS @ / (dev 20005a64, opts ) -> 20005a74 [Aug 30 19:33:06.102] mgos_vfs_mount /: size 233681, used: 4016, free: 229665 [Aug 30 19:33:06.108] mgos_vfs_mount Mount SLFS @ /slfs (dev 0, opts ) -> 20005ed4 [Aug 30 19:33:06.114] mgos_vfs_mount /slfs: size 0, used: 0, free: 0 [Aug 30 19:33:06.718] mgos_sys_config_init MAC: 04A316459442 [Aug 30 19:33:06.720] mgos_sys_config_init WDT: 30 seconds [Aug 30 19:33:06.724] Hello, world! [Aug 30 19:33:06.728] mgos_init Init done, RAM: 253588 total, 236544 free, 235864 min free ``` PUBLISHED_FROM=7e83c9ddcc642bd324a40e125d6636ece824fb18 --- common/platforms/simplelink/cs_simplelink.h | 1 + mjs.c | 1 + 2 files changed, 2 insertions(+) diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index 684c518..ce8b8f7 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -127,6 +127,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED #define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME #define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE +#define SL_NETCFG_MAC_ADDRESS_GET SL_MAC_ADDRESS_GET #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET diff --git a/mjs.c b/mjs.c index 12b9985..4022a1a 100644 --- a/mjs.c +++ b/mjs.c @@ -726,6 +726,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED #define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME #define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE +#define SL_NETCFG_MAC_ADDRESS_GET SL_MAC_ADDRESS_GET #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET From 742def6a87008ccd88b0d36e7f91aef8570f795f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 31 Aug 2017 18:23:11 +0300 Subject: [PATCH 082/265] CC3220: WiFi, basic networking support PUBLISHED_FROM=db89a45a536f0234d6d5cf740354c0dbeeff1f26 --- common/platforms/simplelink/cs_simplelink.h | 6 ++++-- mjs.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index ce8b8f7..4257f35 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -142,7 +142,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION -#define SL_DEV_GET_LEN_TYPE _u8 +#define SL_LEN_TYPE _u8 +#define SL_OPT_TYPE _u8 #else /* SL_MAJOR_VERSION_NUM >= 2 */ @@ -151,7 +152,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_FI_FILE_SIZE(fi) ((fi).Len) #define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) -#define SL_DEV_GET_LEN_TYPE _u16 +#define SL_LEN_TYPE _u16 +#define SL_OPT_TYPE _u16 #endif /* SL_MAJOR_VERSION_NUM < 2 */ diff --git a/mjs.c b/mjs.c index 4022a1a..7e3f819 100644 --- a/mjs.c +++ b/mjs.c @@ -741,7 +741,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION -#define SL_DEV_GET_LEN_TYPE _u8 +#define SL_LEN_TYPE _u8 +#define SL_OPT_TYPE _u8 #else /* SL_MAJOR_VERSION_NUM >= 2 */ @@ -750,7 +751,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_FI_FILE_SIZE(fi) ((fi).Len) #define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) -#define SL_DEV_GET_LEN_TYPE _u16 +#define SL_LEN_TYPE _u16 +#define SL_OPT_TYPE _u16 #endif /* SL_MAJOR_VERSION_NUM < 2 */ From 033a1dfbfea9e70c516b36b8351bbf6e9dc64fb5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 1 Sep 2017 00:35:11 +0300 Subject: [PATCH 083/265] CC3220: AWS connection works PUBLISHED_FROM=5831462c5be0b79afff32130a1f45784f32bc524 --- common/platforms/simplelink/sl_net_if.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/platforms/simplelink/sl_net_if.c b/common/platforms/simplelink/sl_net_if.c index ab4894b..2619925 100644 --- a/common/platforms/simplelink/sl_net_if.c +++ b/common/platforms/simplelink/sl_net_if.c @@ -241,7 +241,15 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { DBG(("%p conn res=%d", nc, nc->err)); if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY || /* TODO(rojer): Provide API to set the date for verification. */ - nc->err == SL_ERROR_BSD_ESECDATEERROR) { + nc->err == SL_ERROR_BSD_ESECDATEERROR +#if SL_MAJOR_VERSION_NUM >= 2 + /* Per SWRU455, this error does not mean verification failed, + * it only means that the cert used is not present in the trusted + * root CA catalog. Which is perfectly fine. */ + || + nc->err == SL_ERROR_BSD_ESECUNKNOWNROOTCA +#endif + ) { nc->err = 0; } if (nc->flags & MG_F_SSL && nc->err == 0) { From 380639f8f3a3ee86069edb33c5948e4f25ae3806 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 1 Sep 2017 09:23:26 +0100 Subject: [PATCH 084/265] CC3220: JS support; default app builds and works This PR includes a dummy updater implementation PUBLISHED_FROM=044146d6051fcd92ddb103be407163675de6543f --- mjs.c | 2 +- mjs/src/mjs_ffi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index 7e3f819..eeeef54 100644 --- a/mjs.c +++ b/mjs.c @@ -9869,7 +9869,7 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { ret = MJS_TYPE_ERROR; mjs_prepend_errorf(mjs, ret, "actual arg #%d is not a function, but %s", i, - mjs_stringify_type(arg)); + mjs_stringify_type((enum mjs_type) arg)); goto clean; } break; diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index 919960f..e090ff9 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -778,7 +778,7 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { ret = MJS_TYPE_ERROR; mjs_prepend_errorf(mjs, ret, "actual arg #%d is not a function, but %s", i, - mjs_stringify_type(arg)); + mjs_stringify_type((enum mjs_type) arg)); goto clean; } break; From 0b242b5e9d5dd4d057664a30477f1347cb47a06e Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 12 Sep 2017 19:08:43 +0300 Subject: [PATCH 085/265] Add cs_timegm Which is a slightly modified version from https://stackoverflow.com/questions/283166/easy-way-to-convert-a-struct-tm-expressed-in-utc-to-time-t-type PUBLISHED_FROM=b73f920ca42c45473c23337782e815306bdf69f1 --- common/cs_time.c | 35 +++++++++++++++++++++++++++++++++++ common/cs_time.h | 8 ++++++++ mjs.c | 8 ++++++++ 3 files changed, 51 insertions(+) diff --git a/common/cs_time.c b/common/cs_time.c index 7eaa4c3..f21845c 100644 --- a/common/cs_time.c +++ b/common/cs_time.c @@ -46,3 +46,38 @@ double cs_time(void) { #endif /* _WIN32 */ return now; } + +double cs_timegm(const struct tm *tm) { + /* Month-to-day offset for non-leap-years. */ + static const int month_day[12] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + + /* Most of the calculation is easy; leap years are the main difficulty. */ + int month = tm->tm_mon % 12; + int year = tm->tm_year + tm->tm_mon / 12; + int year_for_leap; + int64_t rt; + + if (month < 0) { /* Negative values % 12 are still negative. */ + month += 12; + --year; + } + + /* This is the number of Februaries since 1900. */ + year_for_leap = (month > 1) ? year + 1 : year; + + rt = + tm->tm_sec /* Seconds */ + + + 60 * + (tm->tm_min /* Minute = 60 seconds */ + + + 60 * (tm->tm_hour /* Hour = 60 minutes */ + + + 24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */ + + 365 * (year - 70) /* Year = 365 days */ + + (year_for_leap - 69) / 4 /* Every 4 years is leap... */ + - (year_for_leap - 1) / 100 /* Except centuries... */ + + (year_for_leap + 299) / 400))); /* Except 400s. */ + return rt < 0 ? -1 : (double) rt; +} diff --git a/common/cs_time.h b/common/cs_time.h index 4d3e716..3b59073 100644 --- a/common/cs_time.h +++ b/common/cs_time.h @@ -6,6 +6,8 @@ #ifndef CS_COMMON_CS_TIME_H_ #define CS_COMMON_CS_TIME_H_ +#include + #include "common/platform.h" #ifdef __cplusplus @@ -15,6 +17,12 @@ extern "C" { /* Sub-second granularity time(). */ double cs_time(void); +/* + * Similar to (non-standard) timegm, converts broken-down time into the number + * of seconds since Unix Epoch. + */ +double cs_timegm(const struct tm *tm); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mjs.c b/mjs.c index eeeef54..c401ad1 100644 --- a/mjs.c +++ b/mjs.c @@ -1644,6 +1644,8 @@ void cs_log_printf(const char *fmt, ...) #ifndef CS_COMMON_CS_TIME_H_ #define CS_COMMON_CS_TIME_H_ +#include + /* Amalgamated: #include "common/platform.h" */ #ifdef __cplusplus @@ -1653,6 +1655,12 @@ extern "C" { /* Sub-second granularity time(). */ double cs_time(void); +/* + * Similar to (non-standard) timegm, converts broken-down time into the number + * of seconds since Unix Epoch. + */ +double cs_timegm(const struct tm *tm); + #ifdef __cplusplus } #endif /* __cplusplus */ From a63e21ebc1ee4ab21b9094843c385840d7859f69 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 13 Sep 2017 16:20:46 +0300 Subject: [PATCH 086/265] Make mjs_arg, mjs_nargs and mjs_return public To make writing cfunctions possible. PUBLISHED_FROM=46c673ce9f88867269284844538dd2ee1d778272 --- mjs.c | 26 ++++++++++++++++++++------ mjs.h | 34 ++++++++++++++++++++++++++++++++++ mjs/src/mjs_core.c | 6 +++--- mjs/src/mjs_core.h | 3 --- mjs/src/mjs_core_public.h | 17 +++++++++++++++++ 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/mjs.c b/mjs.c index c401ad1..c7c1877 100644 --- a/mjs.c +++ b/mjs.c @@ -2478,6 +2478,23 @@ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); */ void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); +/* + * When invoked from a cfunction, returns number of arguments passed to the + * current JS function call. + */ +int mjs_nargs(struct mjs *mjs); + +/* + * When invoked from a cfunction, returns n-th argument to the current JS + * function call. + */ +mjs_val_t mjs_arg(struct mjs *mjs, int n); + +/* + * Sets return value for the current JS function call. + */ +void mjs_return(struct mjs *mjs, mjs_val_t v); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -3016,9 +3033,6 @@ enum mjs_header_items { MJS_PRIVATE size_t mjs_get_func_addr(mjs_val_t v); MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs); -MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index); -MJS_PRIVATE int mjs_nargs(struct mjs *mjs); -MJS_PRIVATE void mjs_return(struct mjs *mjs, mjs_val_t); MJS_PRIVATE enum mjs_type mjs_get_type(mjs_val_t v); @@ -7859,14 +7873,14 @@ MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs) { return pos; } -MJS_PRIVATE int mjs_nargs(struct mjs *mjs) { +int mjs_nargs(struct mjs *mjs) { int top = mjs_stack_size(&mjs->stack); int pos = mjs_getretvalpos(mjs) + 1; // LOG(LL_INFO, ("top: %d pos: %d", top, pos)); return pos > 0 && pos < top ? top - pos : 0; } -MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { +mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { mjs_val_t res = MJS_UNDEFINED; int top = mjs_stack_size(&mjs->stack); int pos = mjs_getretvalpos(mjs) + 1; @@ -7877,7 +7891,7 @@ MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { return res; } -MJS_PRIVATE void mjs_return(struct mjs *mjs, mjs_val_t v) { +void mjs_return(struct mjs *mjs, mjs_val_t v) { int pos = mjs_getretvalpos(mjs); // LOG(LL_INFO, ("pos: %d", pos)); mjs->stack.len = sizeof(mjs_val_t) * pos; diff --git a/mjs.h b/mjs.h index 2adbce4..00ff906 100644 --- a/mjs.h +++ b/mjs.h @@ -262,6 +262,23 @@ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); */ void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); +/* + * When invoked from a cfunction, returns number of arguments passed to the + * current JS function call. + */ +int mjs_nargs(struct mjs *mjs); + +/* + * When invoked from a cfunction, returns n-th argument to the current JS + * function call. + */ +mjs_val_t mjs_arg(struct mjs *mjs, int n); + +/* + * Sets return value for the current JS function call. + */ +void mjs_return(struct mjs *mjs, mjs_val_t v); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -527,6 +544,23 @@ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); */ void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); +/* + * When invoked from a cfunction, returns number of arguments passed to the + * current JS function call. + */ +int mjs_nargs(struct mjs *mjs); + +/* + * When invoked from a cfunction, returns n-th argument to the current JS + * function call. + */ +mjs_val_t mjs_arg(struct mjs *mjs, int n); + +/* + * Sets return value for the current JS function call. + */ +void mjs_return(struct mjs *mjs, mjs_val_t v); + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/mjs/src/mjs_core.c b/mjs/src/mjs_core.c index d0ab01d..f058abe 100644 --- a/mjs/src/mjs_core.c +++ b/mjs/src/mjs_core.c @@ -311,14 +311,14 @@ MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs) { return pos; } -MJS_PRIVATE int mjs_nargs(struct mjs *mjs) { +int mjs_nargs(struct mjs *mjs) { int top = mjs_stack_size(&mjs->stack); int pos = mjs_getretvalpos(mjs) + 1; // LOG(LL_INFO, ("top: %d pos: %d", top, pos)); return pos > 0 && pos < top ? top - pos : 0; } -MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { +mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { mjs_val_t res = MJS_UNDEFINED; int top = mjs_stack_size(&mjs->stack); int pos = mjs_getretvalpos(mjs) + 1; @@ -329,7 +329,7 @@ MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) { return res; } -MJS_PRIVATE void mjs_return(struct mjs *mjs, mjs_val_t v) { +void mjs_return(struct mjs *mjs, mjs_val_t v) { int pos = mjs_getretvalpos(mjs); // LOG(LL_INFO, ("pos: %d", pos)); mjs->stack.len = sizeof(mjs_val_t) * pos; diff --git a/mjs/src/mjs_core.h b/mjs/src/mjs_core.h index 3aea4d3..aab7a3a 100644 --- a/mjs/src/mjs_core.h +++ b/mjs/src/mjs_core.h @@ -155,9 +155,6 @@ enum mjs_header_items { MJS_PRIVATE size_t mjs_get_func_addr(mjs_val_t v); MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs); -MJS_PRIVATE mjs_val_t mjs_arg(struct mjs *mjs, int arg_index); -MJS_PRIVATE int mjs_nargs(struct mjs *mjs); -MJS_PRIVATE void mjs_return(struct mjs *mjs, mjs_val_t); MJS_PRIVATE enum mjs_type mjs_get_type(mjs_val_t v); diff --git a/mjs/src/mjs_core_public.h b/mjs/src/mjs_core_public.h index c964107..b374fdd 100644 --- a/mjs/src/mjs_core_public.h +++ b/mjs/src/mjs_core_public.h @@ -203,6 +203,23 @@ const char *mjs_strerror(struct mjs *mjs, enum mjs_err err); */ void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc); +/* + * When invoked from a cfunction, returns number of arguments passed to the + * current JS function call. + */ +int mjs_nargs(struct mjs *mjs); + +/* + * When invoked from a cfunction, returns n-th argument to the current JS + * function call. + */ +mjs_val_t mjs_arg(struct mjs *mjs, int n); + +/* + * Sets return value for the current JS function call. + */ +void mjs_return(struct mjs *mjs, mjs_val_t v); + #if defined(__cplusplus) } #endif /* __cplusplus */ From 46c078ec0472863c19e3e0ff2118980e091bfe03 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 14 Sep 2017 14:00:41 +0300 Subject: [PATCH 087/265] Acquire lock when manipulating rx in SSL recv path PUBLISHED_FROM=a34cfa3ebc12daf75d7f24c8d3f3707dcc33d9a2 --- common/platforms/lwip/mg_lwip_ssl_if.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/platforms/lwip/mg_lwip_ssl_if.c b/common/platforms/lwip/mg_lwip_ssl_if.c index fded431..ef03d54 100644 --- a/common/platforms/lwip/mg_lwip_ssl_if.c +++ b/common/platforms/lwip/mg_lwip_ssl_if.c @@ -183,6 +183,7 @@ int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { } size_t seg_len = (seg->len - cs->rx_offset); DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len)); + mgos_lock(); len = MIN(len, seg_len); pbuf_copy_partial(seg, buf, len, cs->rx_offset); cs->rx_offset += len; @@ -194,6 +195,7 @@ int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { pbuf_free(seg); cs->rx_offset = 0; } + mgos_unlock(); LOG(LL_DEBUG, ("%p <- %d", nc, (int) len)); return len; } From 7cc4852369718d7c408375d1aecd541e71bf62d2 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 14 Sep 2017 14:45:11 +0100 Subject: [PATCH 088/265] Do not double-count recved bytes Mongoose would report consumed bytes twice if mg_call is invoked recursively (e.g. proto_handler uses mg_call to invoke user's handler). Reporting twice as much recved as was delivered effectively disables LwIP's TCP throttling and causes buffers to grow too big. PUBLISHED_FROM=4ad5cd5db4dd54623bd6de2d50d32ddcc9e2b08a --- common/platforms/lwip/mg_lwip_net_if.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 59e2e52..e05f4d2 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -153,6 +153,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *q = p->next; for (; q != NULL; q = q->next) pbuf_ref(q); } + mgos_lock(); if (cs->rx_chain == NULL) { cs->rx_offset = 0; } else if (pbuf_clen(cs->rx_chain) >= 4) { @@ -166,6 +167,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, p = np; } } + mgos_unlock(); mg_lwip_recv_common(nc, p); return ERR_OK; } @@ -643,7 +645,8 @@ void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { DBG(("%p invalid socket", nc)); return; } - DBG(("%p %p %u", nc, cs->pcb.tcp, len)); + DBG(("%p %p %u %u", nc, cs->pcb.tcp, len, + (cs->rx_chain ? cs->rx_chain->tot_len : 0))); struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; #if MG_ENABLE_SSL if (!(nc->flags & MG_F_SSL)) { From 86fe5f95ecc99006e72c8275ba97642d3addf324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sat, 23 Sep 2017 09:39:58 +0100 Subject: [PATCH 089/265] Implement json_fprintf() PUBLISHED_FROM=74a4d40d7b6234ad219020fc9c6815f15392020f --- frozen/frozen.c | 46 +++++++++++++++++++++++++++++++++++++ frozen/frozen.h | 15 +++++++++++- mjs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 735989d..62de906 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -1016,3 +1016,49 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { va_end(ap); return result; } + +int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK; +int json_vfprintf(const char *file_name, const char *fmt, va_list ap) { + int res = -1; + FILE *fp = fopen(file_name, "w"); + if (fp != NULL) { + struct json_out out = JSON_OUT_FILE(fp); + res = json_vprintf(&out, fmt, ap); + fputc('\n', fp); + fclose(fp); + } + return res; +} + +int json_fprintf(const char *file_name, const char *fmt, ...) WEAK; +int json_fprintf(const char *file_name, const char *fmt, ...) { + int result; + va_list ap; + va_start(ap, fmt); + result = json_vfprintf(file_name, fmt, ap); + va_end(ap); + return result; +} + +char *json_fread(const char *path) WEAK; +char *json_fread(const char *path) { + FILE *fp; + char *data = NULL; + if ((fp = fopen(path, "rb")) == NULL) { + } else if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + } else { + size_t size = ftell(fp); + data = (char *) malloc(size + 1); + if (data != NULL) { + fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */ + if (fread(data, 1, size, fp) != size) { + free(data); + return NULL; + } + data[size] = '\0'; + } + fclose(fp); + } + return data; +} diff --git a/frozen/frozen.h b/frozen/frozen.h index 3ac3a98..ee235f8 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -133,7 +133,7 @@ extern int json_printer_file(struct json_out *, const char *, size_t); #define JSON_OUT_FILE(fp) \ { \ json_printer_file, { \ - { (void *) fp, 0, 0 } \ + { (char *) fp, 0, 0 } \ } \ } @@ -157,6 +157,13 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); int json_printf(struct json_out *, const char *fmt, ...); int json_vprintf(struct json_out *, const char *fmt, va_list ap); +/* + * Same as json_printf, but prints to a file. + * File is created if does not exist. File is truncated if already exists. + */ +int json_fprintf(const char *file_name, const char *fmt, ...); +int json_vfprintf(const char *file_name, const char *fmt, va_list ap); + /* * Helper %M callback that prints contiguous C arrays. * Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt @@ -220,6 +227,12 @@ int json_unescape(const char *src, int slen, char *dst, int dlen); */ int json_escape(struct json_out *out, const char *str, size_t str_len); +/* + * Read the whole file in memory. + * Return malloc-ed file content, or NULL on error. The caller must free(). + */ +char *json_fread(const char *file_name); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mjs.c b/mjs.c index c7c1877..11b2678 100644 --- a/mjs.c +++ b/mjs.c @@ -3672,7 +3672,7 @@ extern int json_printer_file(struct json_out *, const char *, size_t); #define JSON_OUT_FILE(fp) \ { \ json_printer_file, { \ - { (void *) fp, 0, 0 } \ + { (char *) fp, 0, 0 } \ } \ } @@ -3696,6 +3696,13 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); int json_printf(struct json_out *, const char *fmt, ...); int json_vprintf(struct json_out *, const char *fmt, va_list ap); +/* + * Same as json_printf, but prints to a file. + * File is created if does not exist. File is truncated if already exists. + */ +int json_fprintf(const char *file_name, const char *fmt, ...); +int json_vfprintf(const char *file_name, const char *fmt, va_list ap); + /* * Helper %M callback that prints contiguous C arrays. * Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt @@ -3759,6 +3766,12 @@ int json_unescape(const char *src, int slen, char *dst, int dlen); */ int json_escape(struct json_out *out, const char *str, size_t str_len); +/* + * Read the whole file in memory. + * Return malloc-ed file content, or NULL on error. The caller must free(). + */ +char *json_fread(const char *file_name); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -6381,6 +6394,52 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { va_end(ap); return result; } + +int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK; +int json_vfprintf(const char *file_name, const char *fmt, va_list ap) { + int res = -1; + FILE *fp = fopen(file_name, "w"); + if (fp != NULL) { + struct json_out out = JSON_OUT_FILE(fp); + res = json_vprintf(&out, fmt, ap); + fputc('\n', fp); + fclose(fp); + } + return res; +} + +int json_fprintf(const char *file_name, const char *fmt, ...) WEAK; +int json_fprintf(const char *file_name, const char *fmt, ...) { + int result; + va_list ap; + va_start(ap, fmt); + result = json_vfprintf(file_name, fmt, ap); + va_end(ap); + return result; +} + +char *json_fread(const char *path) WEAK; +char *json_fread(const char *path) { + FILE *fp; + char *data = NULL; + if ((fp = fopen(path, "rb")) == NULL) { + } else if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + } else { + size_t size = ftell(fp); + data = (char *) malloc(size + 1); + if (data != NULL) { + fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */ + if (fread(data, 1, size, fp) != size) { + free(data); + return NULL; + } + data[size] = '\0'; + } + fclose(fp); + } + return data; +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.c" #endif From 49ae1e83227932710bebad683fc60346a4d43d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Tue, 26 Sep 2017 01:39:21 +0100 Subject: [PATCH 090/265] Implement json_setf PUBLISHED_FROM=b5f1bd6e292f3d0f65729b5e557544a4eefc1a6f --- frozen/frozen.c | 152 ++++++++++++++++++++++++++++++++++++++---- frozen/frozen.h | 19 ++++++ mjs.c | 171 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 314 insertions(+), 28 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 62de906..bdbb655 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -289,9 +289,9 @@ static int parse_number(struct frozen *f) { static int parse_array(struct frozen *f) { int i = 0, current_path_len; char buf[20]; + CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0); TRY(test_and_skip(f, '[')); { - CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0); { SET_STATE(f, f->cur - 1, "", 0); while (cur(f) != ']') { @@ -375,9 +375,6 @@ static int parse_value(struct frozen *f) { /* key = identifier | string */ static int parse_key(struct frozen *f) { int ch = cur(f); -#if 0 - printf("%s [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur); -#endif if (is_alpha(ch)) { TRY(parse_identifier(f)); } else if (ch == '"') { @@ -408,19 +405,17 @@ static int parse_pair(struct frozen *f) { /* object = '{' pair { ',' pair } '}' */ static int parse_object(struct frozen *f) { + CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0); TRY(test_and_skip(f, '{')); { - CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0); - { - SET_STATE(f, f->cur - 1, ".", 1); - while (cur(f) != '}') { - TRY(parse_pair(f)); - if (cur(f) == ',') f->cur++; - } - TRY(test_and_skip(f, '}')); - truncate_path(f, fstate.path_len); - CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr); + SET_STATE(f, f->cur - 1, ".", 1); + while (cur(f) != '}') { + TRY(parse_pair(f)); + if (cur(f) == ',') f->cur++; } + TRY(test_and_skip(f, '}')); + truncate_path(f, fstate.path_len); + CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr); } return 0; } @@ -1062,3 +1057,132 @@ char *json_fread(const char *path) { } return data; } + +struct json_setf_data { + const char *json_path; + const char *base; /* Pointer to the source JSON string */ + int matched; /* Matched part of json_path */ + int pos; /* Offset of the mutated value begin */ + int end; /* Offset of the mutated value end */ + int prev; /* Offset of the previous token end */ +}; + +static int get_matched_prefix_len(const char *s1, const char *s2) { + int i = 0; + while (s1[i] && s2[i] && s1[i] == s2[i]) i++; + return i; +} + +static void json_vsetf_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct json_setf_data *data = (struct json_setf_data *) userdata; + int off, len = get_matched_prefix_len(path, data->json_path); + if (t->ptr == NULL) return; + off = t->ptr - data->base; + // printf("--%d %s %d\n", t->type, path, off); + if (len > data->matched) data->matched = len; + + /* + * If there is no exact path match, set the mutation position to tbe end + * of the object or array + */ + if (len < data->matched && data->pos == 0 && + (t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END)) { + data->pos = data->end = data->prev; + } + + /* Exact path match. Set mutation position to the value of this token */ + if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START && + t->type != JSON_TYPE_ARRAY_START) { + data->pos = off; + data->end = off + t->len; + } + + /* + * For deletion, we need to know where the previous value ends, because + * we don't know where matched value key starts. + * When the mutation position is not yet set, remember each value end. + * When the mutation position is already set, but it is at the beginning + * of the object/array, we catch the end of the object/array and see + * whether the object/array start is closer then previously stored prev. + */ + if (data->pos == 0) { + data->prev = off + t->len; /* pos is not yet set */ + } else if ((t->ptr[0] == '[' || t->ptr[0] == '{') && off + 1 < data->pos && + off + 1 > data->prev) { + data->prev = off + 1; + } + (void) name; + (void) name_len; +} + +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap) WEAK; +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap) { + struct json_setf_data data; + memset(&data, 0, sizeof(data)); + data.json_path = json_path; + data.base = s; + data.end = len; + // printf("S:[%.*s] %s %p\n", len, s, json_path, json_fmt); + json_walk(s, len, json_vsetf_cb, &data); + // printf("-> %d %d %d\n", data.prev, data.pos, data.end); + if (json_fmt == NULL) { + /* Deletion codepath */ + json_printf(out, "%.*s", data.prev, s); + /* Trim comma after the value that begins at object/array start */ + if (s[data.prev - 1] == '{' || s[data.prev - 1] == '[') { + int i = data.end; + while (i < len && is_space(s[i])) i++; + if (s[i] == ',') data.end = i + 1; /* Point after comma */ + } + json_printf(out, "%.*s", len - data.end, s + data.end); + } else { + /* Modification codepath */ + int n, off = data.matched, depth = 0; + + /* Print the unchanged beginning */ + json_printf(out, "%.*s", data.pos, s); + + /* Add missing keys */ + while ((n = strcspn(&json_path[off], ".[")) > 0) { + if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0) { + json_printf(out, ","); + } + if (off > 0 && json_path[off - 1] != '.') break; + json_printf(out, "%.*Q:", 1, json_path + off); + off += n; + if (json_path[off] != '\0') { + json_printf(out, "%c", json_path[off] == '.' ? '{' : '['); + depth++; + off++; + } + } + /* Print the new value */ + json_vprintf(out, json_fmt, ap); + + /* Close brackets/braces of the added missing keys */ + for (; off > data.matched; off--) { + int ch = json_path[off]; + const char *p = ch == '.' ? "}" : ch == '[' ? "]" : ""; + json_printf(out, "%s", p); + } + + /* Print the rest of the unchanged string */ + json_printf(out, "%.*s", len - data.end, s + data.end); + } + return data.end > data.pos ? 1 : 0; +} + +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...) WEAK; +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...) { + int result; + va_list ap; + va_start(ap, json_fmt); + result = json_vsetf(s, len, out, json_path, json_fmt, ap); + va_end(ap); + return result; +} diff --git a/frozen/frozen.h b/frozen/frozen.h index ee235f8..5f9fa4e 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -233,6 +233,25 @@ int json_escape(struct json_out *out, const char *str, size_t str_len); */ char *json_fread(const char *file_name); +/* + * Update given JSON string `s,len` by changing the value at given `json_path`. + * The result is saved to `out`. If `json_fmt` == NULL, that deletes the key. + * If path is not present, missing keys are added. Array path without an + * index pushes a value to the end of an array. + * Return 1 if the string was changed, 0 otherwise. + * + * Example: s is a JSON string { "a": 1, "b": [ 2 ] } + * json_setf(s, len, out, ".a", "7"); // { "a": 7, "b": [ 2 ] } + * json_setf(s, len, out, ".b", "7"); // { "a": 1, "b": 7 } + * json_setf(s, len, out, ".b[]", "7"); // { "a": 1, "b": [ 2,7 ] } + * json_setf(s, len, out, ".b", NULL); // { "a": 1 } + */ +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...); + +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mjs.c b/mjs.c index 11b2678..9477df7 100644 --- a/mjs.c +++ b/mjs.c @@ -3772,6 +3772,25 @@ int json_escape(struct json_out *out, const char *str, size_t str_len); */ char *json_fread(const char *file_name); +/* + * Update given JSON string `s,len` by changing the value at given `json_path`. + * The result is saved to `out`. If `json_fmt` == NULL, that deletes the key. + * If path is not present, missing keys are added. Array path without an + * index pushes a value to the end of an array. + * Return 1 if the string was changed, 0 otherwise. + * + * Example: s is a JSON string { "a": 1, "b": [ 2 ] } + * json_setf(s, len, out, ".a", "7"); // { "a": 7, "b": [ 2 ] } + * json_setf(s, len, out, ".b", "7"); // { "a": 1, "b": 7 } + * json_setf(s, len, out, ".b[]", "7"); // { "a": 1, "b": [ 2,7 ] } + * json_setf(s, len, out, ".b", NULL); // { "a": 1 } + */ +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...); + +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -5667,9 +5686,9 @@ static int parse_number(struct frozen *f) { static int parse_array(struct frozen *f) { int i = 0, current_path_len; char buf[20]; + CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0); TRY(test_and_skip(f, '[')); { - CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0); { SET_STATE(f, f->cur - 1, "", 0); while (cur(f) != ']') { @@ -5753,9 +5772,6 @@ static int parse_value(struct frozen *f) { /* key = identifier | string */ static int parse_key(struct frozen *f) { int ch = cur(f); -#if 0 - printf("%s [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur); -#endif if (is_alpha(ch)) { TRY(parse_identifier(f)); } else if (ch == '"') { @@ -5786,19 +5802,17 @@ static int parse_pair(struct frozen *f) { /* object = '{' pair { ',' pair } '}' */ static int parse_object(struct frozen *f) { + CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0); TRY(test_and_skip(f, '{')); { - CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0); - { - SET_STATE(f, f->cur - 1, ".", 1); - while (cur(f) != '}') { - TRY(parse_pair(f)); - if (cur(f) == ',') f->cur++; - } - TRY(test_and_skip(f, '}')); - truncate_path(f, fstate.path_len); - CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr); + SET_STATE(f, f->cur - 1, ".", 1); + while (cur(f) != '}') { + TRY(parse_pair(f)); + if (cur(f) == ',') f->cur++; } + TRY(test_and_skip(f, '}')); + truncate_path(f, fstate.path_len); + CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr); } return 0; } @@ -6440,6 +6454,135 @@ char *json_fread(const char *path) { } return data; } + +struct json_setf_data { + const char *json_path; + const char *base; /* Pointer to the source JSON string */ + int matched; /* Matched part of json_path */ + int pos; /* Offset of the mutated value begin */ + int end; /* Offset of the mutated value end */ + int prev; /* Offset of the previous token end */ +}; + +static int get_matched_prefix_len(const char *s1, const char *s2) { + int i = 0; + while (s1[i] && s2[i] && s1[i] == s2[i]) i++; + return i; +} + +static void json_vsetf_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct json_setf_data *data = (struct json_setf_data *) userdata; + int off, len = get_matched_prefix_len(path, data->json_path); + if (t->ptr == NULL) return; + off = t->ptr - data->base; + // printf("--%d %s %d\n", t->type, path, off); + if (len > data->matched) data->matched = len; + + /* + * If there is no exact path match, set the mutation position to tbe end + * of the object or array + */ + if (len < data->matched && data->pos == 0 && + (t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END)) { + data->pos = data->end = data->prev; + } + + /* Exact path match. Set mutation position to the value of this token */ + if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START && + t->type != JSON_TYPE_ARRAY_START) { + data->pos = off; + data->end = off + t->len; + } + + /* + * For deletion, we need to know where the previous value ends, because + * we don't know where matched value key starts. + * When the mutation position is not yet set, remember each value end. + * When the mutation position is already set, but it is at the beginning + * of the object/array, we catch the end of the object/array and see + * whether the object/array start is closer then previously stored prev. + */ + if (data->pos == 0) { + data->prev = off + t->len; /* pos is not yet set */ + } else if ((t->ptr[0] == '[' || t->ptr[0] == '{') && off + 1 < data->pos && + off + 1 > data->prev) { + data->prev = off + 1; + } + (void) name; + (void) name_len; +} + +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap) WEAK; +int json_vsetf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, va_list ap) { + struct json_setf_data data; + memset(&data, 0, sizeof(data)); + data.json_path = json_path; + data.base = s; + data.end = len; + // printf("S:[%.*s] %s %p\n", len, s, json_path, json_fmt); + json_walk(s, len, json_vsetf_cb, &data); + // printf("-> %d %d %d\n", data.prev, data.pos, data.end); + if (json_fmt == NULL) { + /* Deletion codepath */ + json_printf(out, "%.*s", data.prev, s); + /* Trim comma after the value that begins at object/array start */ + if (s[data.prev - 1] == '{' || s[data.prev - 1] == '[') { + int i = data.end; + while (i < len && is_space(s[i])) i++; + if (s[i] == ',') data.end = i + 1; /* Point after comma */ + } + json_printf(out, "%.*s", len - data.end, s + data.end); + } else { + /* Modification codepath */ + int n, off = data.matched, depth = 0; + + /* Print the unchanged beginning */ + json_printf(out, "%.*s", data.pos, s); + + /* Add missing keys */ + while ((n = strcspn(&json_path[off], ".[")) > 0) { + if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0) { + json_printf(out, ","); + } + if (off > 0 && json_path[off - 1] != '.') break; + json_printf(out, "%.*Q:", 1, json_path + off); + off += n; + if (json_path[off] != '\0') { + json_printf(out, "%c", json_path[off] == '.' ? '{' : '['); + depth++; + off++; + } + } + /* Print the new value */ + json_vprintf(out, json_fmt, ap); + + /* Close brackets/braces of the added missing keys */ + for (; off > data.matched; off--) { + int ch = json_path[off]; + const char *p = ch == '.' ? "}" : ch == '[' ? "]" : ""; + json_printf(out, "%s", p); + } + + /* Print the rest of the unchanged string */ + json_printf(out, "%.*s", len - data.end, s + data.end); + } + return data.end > data.pos ? 1 : 0; +} + +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...) WEAK; +int json_setf(const char *s, int len, struct json_out *out, + const char *json_path, const char *json_fmt, ...) { + int result; + va_list ap; + va_start(ap, json_fmt); + result = json_vsetf(s, len, out, json_path, json_fmt, ap); + va_end(ap); + return result; +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.c" #endif From c30e034cf67759c0cb2ad0f722f3f5a2fbc53b47 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 28 Sep 2017 18:16:30 +0100 Subject: [PATCH 091/265] Fix ESP32 flasher stub build PUBLISHED_FROM=e005100d357071e90454f84b64aa45253d32d105 --- common/platforms/esp32/stubs/stub.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/common/platforms/esp32/stubs/stub.ld b/common/platforms/esp32/stubs/stub.ld index 663b4e0..6c2af65 100644 --- a/common/platforms/esp32/stubs/stub.ld +++ b/common/platforms/esp32/stubs/stub.ld @@ -40,6 +40,7 @@ SECTIONS { } INCLUDE "components/esp32/ld/esp32.rom.ld" +INCLUDE "components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld" PROVIDE(esp_rom_spiflash_attach = 0x40062a6c); PROVIDE(esp_rom_spiflash_config_clk = 0x40062bc8); From 6a039c091d178dda4ae0d328ea8b253e2bf914a0 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 6 Oct 2017 21:57:29 +0100 Subject: [PATCH 092/265] Fix non-SSL build for ESP8266 PUBLISHED_FROM=234f759dc3e414e1c3e10a644e402806d0a61d2a --- common/platforms/esp8266/esp_crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/platforms/esp8266/esp_crypto.c b/common/platforms/esp8266/esp_crypto.c index 4ed40ae..822dab1 100644 --- a/common/platforms/esp8266/esp_crypto.c +++ b/common/platforms/esp8266/esp_crypto.c @@ -7,6 +7,8 @@ #include #include +#include "mongoose/mongoose.h" + #ifdef RTOS_SDK #include "esp_libc.h" #else From 262edca36d5c3900641768a5eb466a27578b9434 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 10 Oct 2017 17:47:31 +0300 Subject: [PATCH 093/265] BREAKING: Sys config API change Now apps should use getters and setters instead of accessing struct fields directly, e.g. instead of `get_cfg()->update.timeout` it should be `mgos_sys_config_get_update_timeout()` to get the current value, and `mgos_sys_config_set_update_timeout(123)` to update the value. For now, the config structs are public, but they will be made private soon, so use accessors to keep your code working. PUBLISHED_FROM=f7d582421a8d7e4d1ed50a280f2670d8b62f8d45 --- common/cs_dbg.c | 4 ++-- common/cs_dbg.h | 2 +- mjs.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/cs_dbg.c b/common/cs_dbg.c index dab6f90..3128d41 100644 --- a/common/cs_dbg.c +++ b/common/cs_dbg.c @@ -32,8 +32,8 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_set_filter(char *str) WEAK; -void cs_log_set_filter(char *str) { +void cs_log_set_filter(const char *str) WEAK; +void cs_log_set_filter(const char *str) { free(s_filter_pattern); if (str != NULL) { s_filter_pattern = strdup(str); diff --git a/common/cs_dbg.h b/common/cs_dbg.h index 0942de7..0adbf45 100644 --- a/common/cs_dbg.h +++ b/common/cs_dbg.h @@ -40,7 +40,7 @@ enum cs_log_level { void cs_log_set_level(enum cs_log_level level); /* Set log filter. NULL (a default) logs everything. */ -void cs_log_set_filter(char *source_file_name); +void cs_log_set_filter(const char *source_file_name); int cs_log_print_prefix(enum cs_log_level level, const char *func, const char *filename); diff --git a/mjs.c b/mjs.c index 9477df7..b58fb05 100644 --- a/mjs.c +++ b/mjs.c @@ -1590,7 +1590,7 @@ enum cs_log_level { void cs_log_set_level(enum cs_log_level level); /* Set log filter. NULL (a default) logs everything. */ -void cs_log_set_filter(char *source_file_name); +void cs_log_set_filter(const char *source_file_name); int cs_log_print_prefix(enum cs_log_level level, const char *func, const char *filename); @@ -4468,8 +4468,8 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_set_filter(char *str) WEAK; -void cs_log_set_filter(char *str) { +void cs_log_set_filter(const char *str) WEAK; +void cs_log_set_filter(const char *str) { free(s_filter_pattern); if (str != NULL) { s_filter_pattern = strdup(str); From 9eb165ff42c50a202d5fb9c4267adc3fafca26e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sat, 14 Oct 2017 13:01:23 +0100 Subject: [PATCH 094/265] Implement json_prettify, json_prettify_file PUBLISHED_FROM=73b6363c974425d6ceeed9861bb2de03d97f3b1f --- frozen/frozen.c | 94 +++++++++++++++++++++++++++++++++++++++++ frozen/frozen.h | 14 +++++++ mjs.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) diff --git a/frozen/frozen.c b/frozen/frozen.c index bdbb655..82b2824 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -1186,3 +1186,97 @@ int json_setf(const char *s, int len, struct json_out *out, va_end(ap); return result; } + +struct prettify_data { + struct json_out *out; + int level; + int last_token; +}; + +static void indent(struct json_out *out, int level) { + while (level-- > 0) out->printer(out, " ", 2); +} + +static void print_key(struct prettify_data *pd, const char *path, + const char *name, int name_len) { + if (pd->last_token != JSON_TYPE_INVALID && + pd->last_token != JSON_TYPE_ARRAY_START && + pd->last_token != JSON_TYPE_OBJECT_START) { + pd->out->printer(pd->out, ",", 1); + } + if (path[0] != '\0') pd->out->printer(pd->out, "\n", 1); + indent(pd->out, pd->level); + if (path[0] != '\0' && path[strlen(path) - 1] != ']') { + pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, name, (int) name_len); + pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, ": ", 2); + } +} + +static void prettify_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct prettify_data *pd = (struct prettify_data *) userdata; + switch (t->type) { + case JSON_TYPE_OBJECT_START: + case JSON_TYPE_ARRAY_START: + print_key(pd, path, name, name_len); + pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_START ? "[" : "{", + 1); + pd->level++; + break; + case JSON_TYPE_OBJECT_END: + case JSON_TYPE_ARRAY_END: + pd->level--; + if (pd->last_token != JSON_TYPE_INVALID && + pd->last_token != JSON_TYPE_ARRAY_START && + pd->last_token != JSON_TYPE_OBJECT_START) { + pd->out->printer(pd->out, "\n", 1); + indent(pd->out, pd->level); + } + pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_END ? "]" : "}", 1); + break; + case JSON_TYPE_NUMBER: + case JSON_TYPE_NULL: + case JSON_TYPE_TRUE: + case JSON_TYPE_FALSE: + case JSON_TYPE_STRING: + print_key(pd, path, name, name_len); + if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, t->ptr, t->len); + if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1); + break; + default: + break; + } + pd->last_token = t->type; +} + +int json_prettify(const char *s, int len, struct json_out *out) WEAK; +int json_prettify(const char *s, int len, struct json_out *out) { + struct prettify_data pd = { out, 0, JSON_TYPE_INVALID }; + return json_walk(s, len, prettify_cb, &pd); +} + +int json_prettify_file(const char *file_name) WEAK; +int json_prettify_file(const char *file_name) { + int res = -1; + char *s = json_fread(file_name); + FILE *fp; + if (s != NULL && (fp = fopen(file_name, "w")) != NULL) { + struct json_out out = JSON_OUT_FILE(fp); + res = json_prettify(s, strlen(s), &out); + if (res < 0) { + /* On error, restore the old content */ + fclose(fp); + fp = fopen(file_name, "w"); + fseek(fp, 0, SEEK_SET); + fwrite(s, 1, strlen(s), fp); + } else { + fputc('\n', fp); + } + fclose(fp); + } + free(s); + return res; +} diff --git a/frozen/frozen.h b/frozen/frozen.h index 5f9fa4e..6c48ded 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -100,6 +100,7 @@ typedef void (*json_walk_callback_t)(void *callback_data, const char *name, /* * Parse `json_string`, invoking `callback` in a way similar to SAX parsers; * see `json_walk_callback_t`. + * Return number of processed bytes, or a negative error code. */ int json_walk(const char *json_string, int json_string_length, json_walk_callback_t callback, void *callback_data); @@ -252,6 +253,19 @@ int json_setf(const char *s, int len, struct json_out *out, int json_vsetf(const char *s, int len, struct json_out *out, const char *json_path, const char *json_fmt, va_list ap); +/* + * Pretty-print JSON string `s,len` into `out`. + * Return number of processed bytes in `s`. + */ +int json_prettify(const char *s, int len, struct json_out *out); + +/* + * Prettify JSON file `file_name`. + * Return number of processed bytes, or negative number of error. + * On error, file content is not modified. + */ +int json_prettify_file(const char *file_name); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mjs.c b/mjs.c index b58fb05..4be7171 100644 --- a/mjs.c +++ b/mjs.c @@ -3639,6 +3639,7 @@ typedef void (*json_walk_callback_t)(void *callback_data, const char *name, /* * Parse `json_string`, invoking `callback` in a way similar to SAX parsers; * see `json_walk_callback_t`. + * Return number of processed bytes, or a negative error code. */ int json_walk(const char *json_string, int json_string_length, json_walk_callback_t callback, void *callback_data); @@ -3791,6 +3792,19 @@ int json_setf(const char *s, int len, struct json_out *out, int json_vsetf(const char *s, int len, struct json_out *out, const char *json_path, const char *json_fmt, va_list ap); +/* + * Pretty-print JSON string `s,len` into `out`. + * Return number of processed bytes in `s`. + */ +int json_prettify(const char *s, int len, struct json_out *out); + +/* + * Prettify JSON file `file_name`. + * Return number of processed bytes, or negative number of error. + * On error, file content is not modified. + */ +int json_prettify_file(const char *file_name); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -6583,6 +6597,100 @@ int json_setf(const char *s, int len, struct json_out *out, va_end(ap); return result; } + +struct prettify_data { + struct json_out *out; + int level; + int last_token; +}; + +static void indent(struct json_out *out, int level) { + while (level-- > 0) out->printer(out, " ", 2); +} + +static void print_key(struct prettify_data *pd, const char *path, + const char *name, int name_len) { + if (pd->last_token != JSON_TYPE_INVALID && + pd->last_token != JSON_TYPE_ARRAY_START && + pd->last_token != JSON_TYPE_OBJECT_START) { + pd->out->printer(pd->out, ",", 1); + } + if (path[0] != '\0') pd->out->printer(pd->out, "\n", 1); + indent(pd->out, pd->level); + if (path[0] != '\0' && path[strlen(path) - 1] != ']') { + pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, name, (int) name_len); + pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, ": ", 2); + } +} + +static void prettify_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct prettify_data *pd = (struct prettify_data *) userdata; + switch (t->type) { + case JSON_TYPE_OBJECT_START: + case JSON_TYPE_ARRAY_START: + print_key(pd, path, name, name_len); + pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_START ? "[" : "{", + 1); + pd->level++; + break; + case JSON_TYPE_OBJECT_END: + case JSON_TYPE_ARRAY_END: + pd->level--; + if (pd->last_token != JSON_TYPE_INVALID && + pd->last_token != JSON_TYPE_ARRAY_START && + pd->last_token != JSON_TYPE_OBJECT_START) { + pd->out->printer(pd->out, "\n", 1); + indent(pd->out, pd->level); + } + pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_END ? "]" : "}", 1); + break; + case JSON_TYPE_NUMBER: + case JSON_TYPE_NULL: + case JSON_TYPE_TRUE: + case JSON_TYPE_FALSE: + case JSON_TYPE_STRING: + print_key(pd, path, name, name_len); + if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1); + pd->out->printer(pd->out, t->ptr, t->len); + if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1); + break; + default: + break; + } + pd->last_token = t->type; +} + +int json_prettify(const char *s, int len, struct json_out *out) WEAK; +int json_prettify(const char *s, int len, struct json_out *out) { + struct prettify_data pd = { out, 0, JSON_TYPE_INVALID }; + return json_walk(s, len, prettify_cb, &pd); +} + +int json_prettify_file(const char *file_name) WEAK; +int json_prettify_file(const char *file_name) { + int res = -1; + char *s = json_fread(file_name); + FILE *fp; + if (s != NULL && (fp = fopen(file_name, "w")) != NULL) { + struct json_out out = JSON_OUT_FILE(fp); + res = json_prettify(s, strlen(s), &out); + if (res < 0) { + /* On error, restore the old content */ + fclose(fp); + fp = fopen(file_name, "w"); + fseek(fp, 0, SEEK_SET); + fwrite(s, 1, strlen(s), fp); + } else { + fputc('\n', fp); + } + fclose(fp); + } + free(s); + return res; +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.c" #endif From 36529f5e7cbc2a200e8658b0c2ba0a16895d4ac1 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 19 Oct 2017 14:41:51 +0100 Subject: [PATCH 095/265] Make amalgam work on windows PUBLISHED_FROM=92f43c7b0a705ff40c4aea07f2ee0627f8e0e4a1 --- tools/amalgam.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/amalgam.py b/tools/amalgam.py index 19291d1..3776d12 100755 --- a/tools/amalgam.py +++ b/tools/amalgam.py @@ -99,9 +99,9 @@ def resolve(path, parent_name): else: p = os.path.join(args.include_path, path) if os.path.exists(p) and not args.norel: - p = os.path.realpath(p).replace('%s/' % os.getcwd(), '') + p = os.path.realpath(p).replace('%s%s' % (os.getcwd(), os.sep), '') # print >>sys.stderr, '%s -> %s (cwd %s)' % (path, p, os.getcwd()) - return p + return p.replace(os.sep, '/') def emit_line_directive(out, name, parent_name): print >>out, '''#ifdef %(prefix)s_MODULE_LINES @@ -148,6 +148,10 @@ def emit_file(out, name, parent_name): # emitting +if sys.platform == "win32": + import os, msvcrt + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + if args.public: print '#include "%s"' % (args.public) From 0d7c2483e098b664dc57f9c144ae090844f5524a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sun, 22 Oct 2017 22:30:16 +0100 Subject: [PATCH 096/265] Implement json_next_key(), json_next_elem() PUBLISHED_FROM=27e4ae61d38f9236df5cd91d56dc6912176b4dea --- frozen/frozen.c | 77 +++++++++++++++++++++++++++++++++++ frozen/frozen.h | 27 +++++++++++++ mjs.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/frozen/frozen.c b/frozen/frozen.c index 82b2824..62ebbcf 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -1280,3 +1280,80 @@ int json_prettify_file(const char *file_name) { free(s); return res; } + +struct next_data { + void *handle; // Passed handle. Changed if a next entry is found + const char *path; // Path to the iterated object/array + int path_len; // Path length - optimisation + int found; // Non-0 if found the next entry + struct json_token *key; // Object's key + struct json_token *val; // Object's value + int *idx; // Array index +}; + +static void next_set_key(struct next_data *d, const char *name, int name_len, + int is_array) { + if (is_array) { + /* Array. Set index and reset key */ + if (d->key != NULL) { + d->key->len = 0; + d->key->ptr = NULL; + } + if (d->idx != NULL) *d->idx = atoi(name); + } else { + /* Object. Set key and make index -1 */ + if (d->key != NULL) { + d->key->ptr = name; + d->key->len = name_len; + } + if (d->idx != NULL) *d->idx = -1; + } +} + +static void next_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct next_data *d = (struct next_data *) userdata; + const char *p = path + d->path_len; + if (d->found) return; + if (d->path_len >= (int) strlen(path)) return; + if (strchr(p, '.') != NULL) return; /* More nested objects - skip */ + if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */ + + // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key. + if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) { + // printf("SAV %s %d %p\n", path, t->type, t->ptr); + next_set_key(d, name, name_len, p[0] == '['); + } else if (d->handle == NULL || d->handle < (void *) t->ptr) { + // printf("END %s %d %p\n", path, t->type, t->ptr); + if (t->type != JSON_TYPE_OBJECT_END && t->type != JSON_TYPE_ARRAY_END) { + next_set_key(d, name, name_len, p[0] == '['); + } + if (d->val != NULL) *d->val = *t; + d->handle = (void *) t->ptr; + d->found = 1; + } +} + +static void *json_next(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val, int *i) { + struct json_token tmpval, *v = val == NULL ? &tmpval : val; + struct json_token tmpkey, *k = key == NULL ? &tmpkey : key; + int tmpidx, *pidx = i == NULL ? &tmpidx : i; + struct next_data data = {handle, path, strlen(path), 0, k, v, pidx}; + json_walk(s, len, next_cb, &data); + return data.found ? data.handle : NULL; +} + +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val) WEAK; +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val) { + return json_next(s, len, handle, path, key, val, NULL); +} + +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val) WEAK; +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val) { + return json_next(s, len, handle, path, NULL, val, idx); +} diff --git a/frozen/frozen.h b/frozen/frozen.h index 6c48ded..c07de82 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -266,6 +266,33 @@ int json_prettify(const char *s, int len, struct json_out *out); */ int json_prettify_file(const char *file_name); +/* + * Iterate over an object at given JSON `path`. + * On each iteration, fill the `key` and `val` tokens. It is OK to pass NULL + * for `key`, or `val`, in which case they won't be populated. + * Return an opaque value suitable for the next iteration, or NULL when done. + * + * Example: + * + * ```c + * void *h = NULL; + * struct json_token key, val; + * while ((h = json_next_key(s, len, h, ".foo", &key, &val)) != NULL) { + * printf("[%.*s] -> [%.*s]\n", key.len, key.ptr, val.len, val.ptr); + * } + * ``` + */ +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val); + + +/* + * Iterate over an array at given JSON `path`. + * Similar to `json_next_key`, but fills array index `idx` instead of `key`. + */ +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mjs.c b/mjs.c index 4be7171..a3b49d6 100644 --- a/mjs.c +++ b/mjs.c @@ -3805,6 +3805,33 @@ int json_prettify(const char *s, int len, struct json_out *out); */ int json_prettify_file(const char *file_name); +/* + * Iterate over an object at given JSON `path`. + * On each iteration, fill the `key` and `val` tokens. It is OK to pass NULL + * for `key`, or `val`, in which case they won't be populated. + * Return an opaque value suitable for the next iteration, or NULL when done. + * + * Example: + * + * ```c + * void *h = NULL; + * struct json_token key, val; + * while ((h = json_next_key(s, len, h, ".foo", &key, &val)) != NULL) { + * printf("[%.*s] -> [%.*s]\n", key.len, key.ptr, val.len, val.ptr); + * } + * ``` + */ +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val); + + +/* + * Iterate over an array at given JSON `path`. + * Similar to `json_next_key`, but fills array index `idx` instead of `key`. + */ +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -6691,6 +6718,83 @@ int json_prettify_file(const char *file_name) { free(s); return res; } + +struct next_data { + void *handle; // Passed handle. Changed if a next entry is found + const char *path; // Path to the iterated object/array + int path_len; // Path length - optimisation + int found; // Non-0 if found the next entry + struct json_token *key; // Object's key + struct json_token *val; // Object's value + int *idx; // Array index +}; + +static void next_set_key(struct next_data *d, const char *name, int name_len, + int is_array) { + if (is_array) { + /* Array. Set index and reset key */ + if (d->key != NULL) { + d->key->len = 0; + d->key->ptr = NULL; + } + if (d->idx != NULL) *d->idx = atoi(name); + } else { + /* Object. Set key and make index -1 */ + if (d->key != NULL) { + d->key->ptr = name; + d->key->len = name_len; + } + if (d->idx != NULL) *d->idx = -1; + } +} + +static void next_cb(void *userdata, const char *name, size_t name_len, + const char *path, const struct json_token *t) { + struct next_data *d = (struct next_data *) userdata; + const char *p = path + d->path_len; + if (d->found) return; + if (d->path_len >= (int) strlen(path)) return; + if (strchr(p, '.') != NULL) return; /* More nested objects - skip */ + if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */ + + // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key. + if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) { + // printf("SAV %s %d %p\n", path, t->type, t->ptr); + next_set_key(d, name, name_len, p[0] == '['); + } else if (d->handle == NULL || d->handle < (void *) t->ptr) { + // printf("END %s %d %p\n", path, t->type, t->ptr); + if (t->type != JSON_TYPE_OBJECT_END && t->type != JSON_TYPE_ARRAY_END) { + next_set_key(d, name, name_len, p[0] == '['); + } + if (d->val != NULL) *d->val = *t; + d->handle = (void *) t->ptr; + d->found = 1; + } +} + +static void *json_next(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val, int *i) { + struct json_token tmpval, *v = val == NULL ? &tmpval : val; + struct json_token tmpkey, *k = key == NULL ? &tmpkey : key; + int tmpidx, *pidx = i == NULL ? &tmpidx : i; + struct next_data data = {handle, path, strlen(path), 0, k, v, pidx}; + json_walk(s, len, next_cb, &data); + return data.found ? data.handle : NULL; +} + +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val) WEAK; +void *json_next_key(const char *s, int len, void *handle, const char *path, + struct json_token *key, struct json_token *val) { + return json_next(s, len, handle, path, key, val, NULL); +} + +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val) WEAK; +void *json_next_elem(const char *s, int len, void *handle, const char *path, + int *idx, struct json_token *val) { + return json_next(s, len, handle, path, NULL, val, idx); +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/ffi/ffi.c" #endif From 2fd6a36ef770b01d10d36e81d6ee46611ee3cc45 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 23 Oct 2017 14:53:01 +0100 Subject: [PATCH 097/265] Fix flashing ESP32-PICO-D4 Add chip type detection PUBLISHED_FROM=96ed8a083ca5e41b29bf57092d48805570f0eb39 --- common/platforms/esp/stub_flasher.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/platforms/esp/stub_flasher.c b/common/platforms/esp/stub_flasher.c index 17d08b4..be7398c 100644 --- a/common/platforms/esp/stub_flasher.c +++ b/common/platforms/esp/stub_flasher.c @@ -29,6 +29,7 @@ #include "ets_sys.h" #include "../../../miniz.c" #elif defined(ESP32) +#include "rom/efuse.h" #include "rom/miniz.h" #include "rom/spi_flash.h" #include "soc/uart_reg.h" @@ -490,10 +491,7 @@ void stub_main1(void) { SelectSpiFunction(); SET_PERI_REG_MASK(0x3FF00014, 1); /* Switch to 160 MHz */ #elif defined(ESP32) - esp_rom_spiflash_attach(0 /* ishspi */, 0 /* legacy */); - /* Set flash to 40 MHz. Note: clkdiv _should_ be 2, but actual meausrement - * shows that with clkdiv = 1 clock is indeed 40 MHz. */ - esp_rom_spiflash_config_clk(1, 1); + esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), 0 /* legacy */); #endif esp_rom_spiflash_config_param( @@ -516,10 +514,6 @@ void stub_main1(void) { SLIP_send(&greeting, 4); #endif - // led_setup(22); - // led_setup(16); - // led_setup(2); - last_cmd = cmd_loop(); ets_delay_us(10000); From bb379e8c76fda53fe1ca020d2631a4a49cf3f5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Mon, 23 Oct 2017 17:02:46 +0100 Subject: [PATCH 098/265] Bug fix + more complex test for json_next PUBLISHED_FROM=a7ca7ec79bb138294449f9b24f4a219c1e57b673 --- frozen/frozen.c | 6 +++--- mjs.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 62ebbcf..5c93682 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -1254,7 +1254,7 @@ static void prettify_cb(void *userdata, const char *name, size_t name_len, int json_prettify(const char *s, int len, struct json_out *out) WEAK; int json_prettify(const char *s, int len, struct json_out *out) { - struct prettify_data pd = { out, 0, JSON_TYPE_INVALID }; + struct prettify_data pd = {out, 0, JSON_TYPE_INVALID}; return json_walk(s, len, prettify_cb, &pd); } @@ -1316,9 +1316,9 @@ static void next_cb(void *userdata, const char *name, size_t name_len, const char *p = path + d->path_len; if (d->found) return; if (d->path_len >= (int) strlen(path)) return; - if (strchr(p, '.') != NULL) return; /* More nested objects - skip */ + if (strncmp(d->path, path, d->path_len) != 0) return; + if (strchr(p + 1, '.') != NULL) return; /* More nested objects - skip */ if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */ - // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key. if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) { // printf("SAV %s %d %p\n", path, t->type, t->ptr); diff --git a/mjs.c b/mjs.c index a3b49d6..26a5fbe 100644 --- a/mjs.c +++ b/mjs.c @@ -6692,7 +6692,7 @@ static void prettify_cb(void *userdata, const char *name, size_t name_len, int json_prettify(const char *s, int len, struct json_out *out) WEAK; int json_prettify(const char *s, int len, struct json_out *out) { - struct prettify_data pd = { out, 0, JSON_TYPE_INVALID }; + struct prettify_data pd = {out, 0, JSON_TYPE_INVALID}; return json_walk(s, len, prettify_cb, &pd); } @@ -6754,9 +6754,9 @@ static void next_cb(void *userdata, const char *name, size_t name_len, const char *p = path + d->path_len; if (d->found) return; if (d->path_len >= (int) strlen(path)) return; - if (strchr(p, '.') != NULL) return; /* More nested objects - skip */ + if (strncmp(d->path, path, d->path_len) != 0) return; + if (strchr(p + 1, '.') != NULL) return; /* More nested objects - skip */ if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */ - // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key. if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) { // printf("SAV %s %d %p\n", path, t->type, t->ptr); From 1f0d7bd4db84629dede06b3a0a8adefcef84e52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Mon, 23 Oct 2017 18:06:15 +0100 Subject: [PATCH 099/265] Default frozen max path 60->256 PUBLISHED_FROM=7c49709cd33db0611e0e5c712c4d29cdb21ac14d --- frozen/frozen.c | 2 +- mjs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frozen/frozen.c b/frozen/frozen.c index 5c93682..a339f9f 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -73,7 +73,7 @@ typedef unsigned _int64 uint64_t; #endif #ifndef JSON_MAX_PATH_LEN -#define JSON_MAX_PATH_LEN 60 +#define JSON_MAX_PATH_LEN 256 #endif struct frozen { diff --git a/mjs.c b/mjs.c index 26a5fbe..f34c20d 100644 --- a/mjs.c +++ b/mjs.c @@ -5511,7 +5511,7 @@ typedef unsigned _int64 uint64_t; #endif #ifndef JSON_MAX_PATH_LEN -#define JSON_MAX_PATH_LEN 60 +#define JSON_MAX_PATH_LEN 256 #endif struct frozen { From 26f975d82326acaeeafb28522c321d143762ee4e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 23 Oct 2017 23:09:11 +0100 Subject: [PATCH 100/265] Fix SimpleLink listener for SSL Must set SSL parameters before invoking sl_Listen PUBLISHED_FROM=9147e7aa945f75e73d5c7cd7987cb5749025a86b --- common/platforms/simplelink/cs_simplelink.h | 2 +- common/platforms/simplelink/sl_net_if.c | 34 ++++++++++----------- common/platforms/simplelink/sl_ssl_if.c | 12 ++++---- mjs.c | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/common/platforms/simplelink/cs_simplelink.h b/common/platforms/simplelink/cs_simplelink.h index 4257f35..ed6afa2 100644 --- a/common/platforms/simplelink/cs_simplelink.h +++ b/common/platforms/simplelink/cs_simplelink.h @@ -101,7 +101,7 @@ int sl_fs_init(void); void sl_restart_cb(struct mg_mgr *mgr); -int sl_set_ssl_opts(struct mg_connection *nc); +int sl_set_ssl_opts(int sock, struct mg_connection *nc); #ifdef __cplusplus } diff --git a/common/platforms/simplelink/sl_net_if.c b/common/platforms/simplelink/sl_net_if.c index 2619925..2a39d14 100644 --- a/common/platforms/simplelink/sl_net_if.c +++ b/common/platforms/simplelink/sl_net_if.c @@ -13,11 +13,10 @@ #define MG_TCP_RECV_BUFFER_SIZE 1024 #define MG_UDP_RECV_BUFFER_SIZE 1500 -static sock_t mg_open_listening_socket(union socket_address *sa, int type, +static sock_t mg_open_listening_socket(struct mg_connection *nc, + union socket_address *sa, int type, int proto); -int sl_set_ssl_opts(struct mg_connection *nc); - void mg_set_non_blocking_mode(sock_t sock) { SlSockNonblocking_t opt; #if SL_MAJOR_VERSION_NUM < 2 @@ -43,7 +42,7 @@ void mg_sl_if_connect_tcp(struct mg_connection *nc, } mg_sock_set(nc, sock); #if MG_ENABLE_SSL - nc->err = sl_set_ssl_opts(nc); + nc->err = sl_set_ssl_opts(sock, nc); if (nc->err != 0) goto out; #endif nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin)); @@ -65,18 +64,14 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) { int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { int proto = 0; if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; - sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto); + sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto); if (sock < 0) return sock; mg_sock_set(nc, sock); -#if MG_ENABLE_SSL - return sl_set_ssl_opts(nc); -#else return 0; -#endif } int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { - sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0); + sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return (errno ? errno : 1); mg_sock_set(nc, sock); return 0; @@ -132,22 +127,27 @@ static int mg_accept_conn(struct mg_connection *lc) { } /* 'sa' must be an initialized address to bind to */ -static sock_t mg_open_listening_socket(union socket_address *sa, int type, +static sock_t mg_open_listening_socket(struct mg_connection *nc, + union socket_address *sa, int type, int proto) { int r; socklen_t sa_len = (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6); sock_t sock = sl_Socket(sa->sa.sa_family, type, proto); if (sock < 0) return sock; - if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) { - sl_Close(sock); - return r; + if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean; + if (type != SOCK_DGRAM) { +#if MG_ENABLE_SSL + if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean; +#endif + if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean; } - if (type != SOCK_DGRAM && (r = sl_Listen(sock, SOMAXCONN)) < 0) { + mg_set_non_blocking_mode(sock); +clean: + if (r < 0) { sl_Close(sock); - return r; + sock = r; } - mg_set_non_blocking_mode(sock); return sock; } diff --git a/common/platforms/simplelink/sl_ssl_if.c b/common/platforms/simplelink/sl_ssl_if.c index 4945880..99642b4 100644 --- a/common/platforms/simplelink/sl_ssl_if.c +++ b/common/platforms/simplelink/sl_ssl_if.c @@ -149,9 +149,9 @@ static char *sl_pem2der(const char *pem_file) { } #endif -int sl_set_ssl_opts(struct mg_connection *nc) { +int sl_set_ssl_opts(int sock, struct mg_connection *nc) { int err; - struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; + const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; DBG(("%p ssl ctx: %p", nc, ctx)); if (ctx != NULL) { @@ -163,11 +163,11 @@ int sl_set_ssl_opts(struct mg_connection *nc) { char *ssl_cert = sl_pem2der(ctx->ssl_cert); char *ssl_key = sl_pem2der(ctx->ssl_key); if (ssl_cert != NULL && ssl_key != NULL) { - err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, strlen(ssl_cert)); LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); - err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key, strlen(ssl_key)); LOG(LL_INFO, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); @@ -182,7 +182,7 @@ int sl_set_ssl_opts(struct mg_connection *nc) { if (ctx->ssl_ca_cert[0] != '\0') { char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); if (ssl_ca_cert != NULL) { - err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, ssl_ca_cert, strlen(ssl_ca_cert)); LOG(LL_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); @@ -194,7 +194,7 @@ int sl_set_ssl_opts(struct mg_connection *nc) { } } if (ctx->ssl_server_name != NULL) { - err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, ctx->ssl_server_name, strlen(ctx->ssl_server_name)); DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); diff --git a/mjs.c b/mjs.c index f34c20d..c2ee8ef 100644 --- a/mjs.c +++ b/mjs.c @@ -700,7 +700,7 @@ int sl_fs_init(void); void sl_restart_cb(struct mg_mgr *mgr); -int sl_set_ssl_opts(struct mg_connection *nc); +int sl_set_ssl_opts(int sock, struct mg_connection *nc); #ifdef __cplusplus } From a800e699d8b5a923abfa0b6d162d93658c2d8e6f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 3 Nov 2017 15:25:25 +0300 Subject: [PATCH 101/265] Avoid unneeded rewrites of rBoot config PUBLISHED_FROM=7b104cea2cb4ca48d01c690e15ad81516577b5fc --- common/platforms/esp8266/rboot/rboot/rboot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/platforms/esp8266/rboot/rboot/rboot.c b/common/platforms/esp8266/rboot/rboot/rboot.c index 62ad3a6..4ac5df1 100644 --- a/common/platforms/esp8266/rboot/rboot/rboot.c +++ b/common/platforms/esp8266/rboot/rboot/rboot.c @@ -4,6 +4,7 @@ // richardaburton@gmail.com // See license.txt for license terms. ////////////////////////////////////////////////// +/* clang-format off */ #ifdef RBOOT_INTEGRATION #include @@ -172,7 +173,7 @@ uint32 NOINLINE find_image(void) { uint32 flashsize; int32 romToBoot; uint8 gpio_boot = FALSE; - uint8 updateConfig = TRUE; + uint8 updateConfig = FALSE; uint8 buffer[SECTOR_SIZE]; rboot_config *romconf = (rboot_config*)buffer; From 4c4a64420dc3e7c893febffb4217f4ed62cde4ae Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 3 Nov 2017 17:39:53 +0300 Subject: [PATCH 102/265] Add ability to update boot loader via OTA Normally boot loader is not updated during OTA because it is too dangerous. However, in (rare) cases where the boot loader itself needs to be updated, a flag in the manifest is provided to enable rewriting bootloader as well. Externally this flag can be set by providing `--build-var MGOS_UPDATE_BOOT_LOADER=true`. PUBLISHED_FROM=d62402f6456d039bb8645c59affd7bef6711152f --- common/platforms/esp8266/rboot/esptool2/esptool2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/platforms/esp8266/rboot/esptool2/esptool2.c b/common/platforms/esp8266/rboot/esptool2/esptool2.c index 707a352..aa9b457 100644 --- a/common/platforms/esp8266/rboot/esptool2/esptool2.c +++ b/common/platforms/esp8266/rboot/esptool2/esptool2.c @@ -18,6 +18,7 @@ * along with esptool2. If not, see . * **********************************************************************************/ +/* clang-format off */ #include #include @@ -394,8 +395,9 @@ int main(int argc, char *argv[]) { bool paramerror = false; bool iromchksum = false; int bootver = 0; - unsigned char mode = 0; - unsigned char size = 0; + /* Overwrite-friendly by default */ + unsigned char mode = 0xff; + unsigned char size = 0xff; unsigned char clock = 0; int opts = 0; From 2aa71671206380a8522a674b6ed2bfbcb9b4e227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Fri, 27 Oct 2017 11:24:27 +0100 Subject: [PATCH 103/265] Make mjs & frozen vc98 & vc2017 friendly PUBLISHED_FROM=7cde8b374d5e318b5cdd69fc5b4de86b2a9552f5 --- README.md | 2 +- common/cs_varint.c | 4 +- common/cs_varint.h | 7 + common/platforms/platform_cc3200.h | 1 + common/platforms/platform_cc3220.h | 1 + common/platforms/platform_esp32.h | 1 + common/platforms/platform_esp8266.h | 1 + common/platforms/platform_unix.h | 1 + common/platforms/platform_windows.h | 15 +- common/str_util.c | 16 +- common/test_util.h | 1 + frozen/frozen.c | 74 +++-- frozen/frozen.h | 4 +- mjs.c | 464 ++++++++++++++++------------ mjs.h | 12 + mjs/Makefile | 78 +++-- mjs/src/ffi/ffi.h | 1 - mjs/src/mjs_bcode.c | 6 +- mjs/src/mjs_builtin.c | 2 +- mjs/src/mjs_core.c | 7 +- mjs/src/mjs_core_public.h | 6 + mjs/src/mjs_dataview.c | 2 +- mjs/src/mjs_exec.c | 89 +++--- mjs/src/mjs_ffi.c | 40 +-- mjs/src/mjs_internal.h | 1 - mjs/src/mjs_parser.c | 97 +++--- mjs/src/mjs_string.c | 8 +- mjs/src/mjs_util.c | 27 +- mjs/tests/unit_test.c | 285 ++++++++++------- 29 files changed, 738 insertions(+), 515 deletions(-) diff --git a/README.md b/README.md index 301383b..90d5276 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ implements a strict subset of ES6 (JavaScript version 6): - Any valid mJS code is a valid ES6 code. - Any valid ES6 code is not necessarily a valid mJS code. -On 32-bit ARM mJS engine takes about 25k of flash memory, and less than 1k +On 32-bit ARM mJS engine takes about 50k of flash memory, and less than 1k of RAM (see [intro article](http://goo.gl/zJYyWF)). mJS is part of [MongooseOS](https://mongoose-os.com), where it enables scripting for IoT devices. diff --git a/common/cs_varint.c b/common/cs_varint.c index 16367b1..ea655f2 100644 --- a/common/cs_varint.c +++ b/common/cs_varint.c @@ -3,9 +3,7 @@ * All rights reserved */ -#include "common/cs_varint.h" - -#include +#include "cs_varint.h" /* * Strings in AST are encoded as tuples (length, string). diff --git a/common/cs_varint.h b/common/cs_varint.h index 229f763..ebe011b 100644 --- a/common/cs_varint.h +++ b/common/cs_varint.h @@ -6,7 +6,14 @@ #ifndef CS_COMMON_CS_VARINT_H_ #define CS_COMMON_CS_VARINT_H_ +#include + +#if defined(_WIN32) && _MSC_VER < 1700 +typedef unsigned char uint8_t; +typedef unsigned __int64 uint64_t; +#else #include +#endif #if defined(__cplusplus) extern "C" { diff --git a/common/platforms/platform_cc3200.h b/common/platforms/platform_cc3200.h index af5580e..1c2033a 100644 --- a/common/platforms/platform_cc3200.h +++ b/common/platforms/platform_cc3200.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/common/platforms/platform_cc3220.h b/common/platforms/platform_cc3220.h index 95ed4cf..a32264a 100644 --- a/common/platforms/platform_cc3220.h +++ b/common/platforms/platform_cc3220.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/common/platforms/platform_esp32.h b/common/platforms/platform_esp32.h index d385e1e..4580f75 100644 --- a/common/platforms/platform_esp32.h +++ b/common/platforms/platform_esp32.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/common/platforms/platform_esp8266.h b/common/platforms/platform_esp8266.h index 88d02ff..5ceb26d 100644 --- a/common/platforms/platform_esp8266.h +++ b/common/platforms/platform_esp8266.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/common/platforms/platform_unix.h b/common/platforms/platform_unix.h index 76d8eda..59a04e3 100644 --- a/common/platforms/platform_unix.h +++ b/common/platforms/platform_unix.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/common/platforms/platform_windows.h b/common/platforms/platform_windows.h index 7b0d655..3b300bd 100644 --- a/common/platforms/platform_windows.h +++ b/common/platforms/platform_windows.h @@ -50,6 +50,12 @@ #include #include +#if _MSC_VER < 1700 +typedef int bool; +#else +#include +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1800 #define strdup _strdup #endif @@ -163,8 +169,15 @@ typedef struct _stati64 cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif -int rmdir(const char *dirname); unsigned int sleep(unsigned int seconds); +/* https://stackoverflow.com/questions/16647819/timegm-cross-platform */ +#define timegm _mkgmtime + +#define gmtime_r(a, b) \ + do { \ + *(b) = *gmtime(a); \ + } while (0) + #endif /* CS_PLATFORM == CS_P_WINDOWS */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ diff --git a/common/str_util.c b/common/str_util.c index 92bcddb..9aa4bcc 100644 --- a/common/str_util.c +++ b/common/str_util.c @@ -384,12 +384,24 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { *buf = NULL; /* LCOV_EXCL_START */ while (len < 0) { MG_FREE(*buf); + if (size == 0) { + size = 5; + } size *= 2; - if ((*buf = (char *) MG_MALLOC(size)) == NULL) break; + if ((*buf = (char *) MG_MALLOC(size)) == NULL) { + len = -1; + break; + } va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); + len = vsnprintf(*buf, size - 1, fmt, ap_copy); va_end(ap_copy); } + + /* + * Microsoft version of vsnprintf() is not always null-terminated, so put + * the terminator manually + */ + (*buf)[len] = 0; /* LCOV_EXCL_STOP */ } else if (len >= (int) size) { /* Standard-compliant code path. Allocate a buffer that is large enough. */ diff --git a/common/test_util.h b/common/test_util.h index 7276f9a..23c5351 100644 --- a/common/test_util.h +++ b/common/test_util.h @@ -68,6 +68,7 @@ void _strfail(const char *a, const char *e, int len); msg = test(); \ elapsed = cs_time() - elapsed; \ printf(" [%.3f] %s\n", elapsed, test_name); \ + fflush(stdout); \ *total_elapsed += elapsed; \ } \ if (msg) return msg; \ diff --git a/frozen/frozen.c b/frozen/frozen.c index a339f9f..ed8bc8b 100644 --- a/frozen/frozen.c +++ b/frozen/frozen.c @@ -35,6 +35,8 @@ #endif #ifdef _WIN32 +#undef snprintf +#undef vsnprintf #define snprintf cs_win_snprintf #define vsnprintf cs_win_vsnprintf int cs_win_snprintf(char *str, size_t size, const char *format, ...); @@ -47,26 +49,20 @@ typedef unsigned _int64 uint64_t; #endif #define PRId64 "I64d" #define PRIu64 "I64u" -#if !defined(SIZE_T_FMT) -#if _MSC_VER >= 1310 -#define SIZE_T_FMT "Iu" -#else -#define SIZE_T_FMT "u" -#endif -#endif #else /* _WIN32 */ /* wants this for C++ */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include -#if !defined(SIZE_T_FMT) -#define SIZE_T_FMT "zu" -#endif #endif /* _WIN32 */ +#ifndef INT64_FMT #define INT64_FMT PRId64 +#endif +#ifndef UINT64_FMT #define UINT64_FMT PRIu64 +#endif #ifndef va_copy #define va_copy(x, y) x = y @@ -502,7 +498,7 @@ static int b64rev(int c) { } } -static uint8_t hexdec(const char *s) { +static unsigned char hexdec(const char *s) { #define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W') int a = tolower(*(const unsigned char *) s); int b = tolower(*(const unsigned char *) (s + 1)); @@ -566,7 +562,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { skip += 2; } else if (fmt[1] == 'z' && fmt[2] == 'u') { size_t val = va_arg(ap, size_t); - snprintf(buf, sizeof(buf), "%" SIZE_T_FMT, val); + snprintf(buf, sizeof(buf), "%lu", (unsigned long) val); len += out->printer(out, buf, strlen(buf)); skip += 1; } else if (fmt[1] == 'M') { @@ -626,29 +622,47 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { */ const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789"; - size_t n = strspn(fmt + 1, end_of_format_specifier); + int n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; - size_t need_len; + int need_len, size = sizeof(buf); char fmt2[20]; - va_list sub_ap; - strncpy(fmt2, fmt, n + 1 > sizeof(fmt2) ? sizeof(fmt2) : n + 1); + va_list ap_copy; + strncpy(fmt2, fmt, + n + 1 > (int) sizeof(fmt2) ? sizeof(fmt2) : (size_t) n + 1); fmt2[n + 1] = '\0'; - va_copy(sub_ap, ap); - need_len = - vsnprintf(buf, sizeof(buf), fmt2, sub_ap) + 1 /* null-term */; - /* - * TODO(lsm): Fix windows & eCos code path here. Their vsnprintf - * implementation returns -1 on overflow rather needed size. - */ - if (need_len > sizeof(buf)) { + va_copy(ap_copy, ap); + need_len = vsnprintf(pbuf, size, fmt2, ap_copy); + va_end(ap_copy); + + if (need_len < 0) { + /* + * Windows & eCos vsnprintf implementation return -1 on overflow + * instead of needed size. + */ + pbuf = NULL; + while (need_len < 0) { + free(pbuf); + size *= 2; + if ((pbuf = (char *) malloc(size)) == NULL) break; + va_copy(ap_copy, ap); + need_len = vsnprintf(pbuf, size, fmt2, ap_copy); + va_end(ap_copy); + } + } else if (need_len >= (int) sizeof(buf)) { /* * resulting string doesn't fit into a stack-allocated buffer `buf`, * so we need to allocate a new buffer from heap and use it */ - pbuf = (char *) malloc(need_len); - va_copy(sub_ap, ap); - vsnprintf(pbuf, need_len, fmt2, sub_ap); + if ((pbuf = (char *) malloc(need_len + 1)) != NULL) { + va_copy(ap_copy, ap); + vsnprintf(pbuf, need_len + 1, fmt2, ap_copy); + va_end(ap_copy); + } + } + if (pbuf == NULL) { + buf[0] = '\0'; + pbuf = buf; } /* @@ -1015,7 +1029,7 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK; int json_vfprintf(const char *file_name, const char *fmt, va_list ap) { int res = -1; - FILE *fp = fopen(file_name, "w"); + FILE *fp = fopen(file_name, "wb"); if (fp != NULL) { struct json_out out = JSON_OUT_FILE(fp); res = json_vprintf(&out, fmt, ap); @@ -1263,13 +1277,13 @@ int json_prettify_file(const char *file_name) { int res = -1; char *s = json_fread(file_name); FILE *fp; - if (s != NULL && (fp = fopen(file_name, "w")) != NULL) { + if (s != NULL && (fp = fopen(file_name, "wb")) != NULL) { struct json_out out = JSON_OUT_FILE(fp); res = json_prettify(s, strlen(s), &out); if (res < 0) { /* On error, restore the old content */ fclose(fp); - fp = fopen(file_name, "w"); + fp = fopen(file_name, "wb"); fseek(fp, 0, SEEK_SET); fwrite(s, 1, strlen(s), fp); } else { diff --git a/frozen/frozen.h b/frozen/frozen.h index c07de82..7cbfb04 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -28,8 +28,9 @@ extern "C" { #include #include -#ifdef _WIN32 +#if defined(_WIN32) && _MSC_VER < 1700 typedef int bool; +enum { false = 0, true = 1 }; #else #include #endif @@ -285,7 +286,6 @@ int json_prettify_file(const char *file_name); void *json_next_key(const char *s, int len, void *handle, const char *path, struct json_token *key, struct json_token *val); - /* * Iterate over an array at given JSON `path`. * Similar to `json_next_key`, but fills array index `idx` instead of `key`. diff --git a/mjs.c b/mjs.c index c2ee8ef..56f0eac 100644 --- a/mjs.c +++ b/mjs.c @@ -178,6 +178,12 @@ #include #include +#if _MSC_VER < 1700 +typedef int bool; +#else +#include +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1800 #define strdup _strdup #endif @@ -291,9 +297,16 @@ typedef struct _stati64 cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif -int rmdir(const char *dirname); unsigned int sleep(unsigned int seconds); +/* https://stackoverflow.com/questions/16647819/timegm-cross-platform */ +#define timegm _mkgmtime + +#define gmtime_r(a, b) \ + do { \ + *(b) = *gmtime(a); \ + } while (0) + #endif /* CS_PLATFORM == CS_P_WINDOWS */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ #ifdef MJS_MODULE_LINES @@ -342,6 +355,7 @@ unsigned int sleep(unsigned int seconds); #include #include #include +#include #include #include #include @@ -461,6 +475,7 @@ typedef struct stat cs_stat_t; #include #include #include +#include #include #include #include @@ -504,6 +519,7 @@ typedef struct stat cs_stat_t; #include #include #include +#include #include #include #include @@ -777,6 +793,7 @@ int slfs_open(const unsigned char *fname, uint32_t flags); #include #include #include +#include #include #include #include @@ -901,6 +918,7 @@ int stat(const char *pathname, struct stat *st); #include #include #include +#include #include #include #include @@ -1919,32 +1937,6 @@ char *cs_mmap_file(const char *path, size_t *size); #endif /* CS_COMMON_CS_FILE_H_ */ #ifdef MJS_MODULE_LINES -#line 1 "common/cs_varint.h" -#endif -/* - * Copyright (c) 2014-2017 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_CS_VARINT_H_ -#define CS_COMMON_CS_VARINT_H_ - -#include - -#if defined(__cplusplus) -extern "C" { -#endif /* __cplusplus */ - -int cs_varint_encode(uint64_t num, uint8_t *to); -uint64_t cs_varint_decode(const uint8_t *from, int *llen); -int cs_varint_llen(uint64_t num); - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_CS_VARINT_H_ */ -#ifdef MJS_MODULE_LINES #line 1 "common/mbuf.h" #endif /* @@ -2073,7 +2065,6 @@ extern "C" { #ifndef MJS_FFI_FFI_H_ #define MJS_FFI_FFI_H_ -#include /* Amalgamated: #include "common/platform.h" */ #if defined(__cplusplus) @@ -2197,7 +2188,6 @@ typedef unsigned long uintptr_t; #define CS_DEFINE_DIRENT #include #else -#include #if defined(__unix__) || defined(__APPLE__) #include #endif @@ -2281,7 +2271,13 @@ typedef unsigned long uintptr_t; #ifndef MJS_CORE_PUBLIC_H_ #define MJS_CORE_PUBLIC_H_ +#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include +#else +typedef unsigned __int64 uint64_t; +typedef int int32_t; +typedef unsigned char uint8_t; +#endif #include #include /* Amalgamated: #include "mjs/src/mjs_license.h" */ @@ -3567,8 +3563,9 @@ extern "C" { #include #include -#ifdef _WIN32 +#if defined(_WIN32) && _MSC_VER < 1700 typedef int bool; +enum { false = 0, true = 1 }; #else #include #endif @@ -3824,7 +3821,6 @@ int json_prettify_file(const char *file_name); void *json_next_key(const char *s, int len, void *handle, const char *path, struct json_token *key, struct json_token *val); - /* * Iterate over an array at given JSON `path`. * Similar to `json_next_key`, but fills array index `idx` instead of `key`. @@ -3946,6 +3942,39 @@ void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out); #endif /* MJS_UTIL_H_ */ #ifdef MJS_MODULE_LINES +#line 1 "common/cs_varint.h" +#endif +/* + * Copyright (c) 2014-2017 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_CS_VARINT_H_ +#define CS_COMMON_CS_VARINT_H_ + +#include + +#if defined(_WIN32) && _MSC_VER < 1700 +typedef unsigned char uint8_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +int cs_varint_encode(uint64_t num, uint8_t *to); +uint64_t cs_varint_decode(const uint8_t *from, int *llen); +int cs_varint_llen(uint64_t num); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_CS_VARINT_H_ */ +#ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_bcode.h" #endif /* @@ -4132,7 +4161,6 @@ typedef unsigned long uintptr_t; #define CS_DEFINE_DIRENT #include #else -#include #if defined(__unix__) || defined(__APPLE__) #include #endif @@ -4639,9 +4667,7 @@ char *cs_mmap_file(const char *path, size_t *size) { * All rights reserved */ -/* Amalgamated: #include "common/cs_varint.h" */ - -#include +/* Amalgamated: #include "cs_varint.h" */ /* * Strings in AST are encoded as tuples (length, string). @@ -5308,12 +5334,24 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { *buf = NULL; /* LCOV_EXCL_START */ while (len < 0) { MG_FREE(*buf); + if (size == 0) { + size = 5; + } size *= 2; - if ((*buf = (char *) MG_MALLOC(size)) == NULL) break; + if ((*buf = (char *) MG_MALLOC(size)) == NULL) { + len = -1; + break; + } va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); + len = vsnprintf(*buf, size - 1, fmt, ap_copy); va_end(ap_copy); } + + /* + * Microsoft version of vsnprintf() is not always null-terminated, so put + * the terminator manually + */ + (*buf)[len] = 0; /* LCOV_EXCL_STOP */ } else if (len >= (int) size) { /* Standard-compliant code path. Allocate a buffer that is large enough. */ @@ -5473,6 +5511,8 @@ int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { #endif #ifdef _WIN32 +#undef snprintf +#undef vsnprintf #define snprintf cs_win_snprintf #define vsnprintf cs_win_vsnprintf int cs_win_snprintf(char *str, size_t size, const char *format, ...); @@ -5485,26 +5525,20 @@ typedef unsigned _int64 uint64_t; #endif #define PRId64 "I64d" #define PRIu64 "I64u" -#if !defined(SIZE_T_FMT) -#if _MSC_VER >= 1310 -#define SIZE_T_FMT "Iu" -#else -#define SIZE_T_FMT "u" -#endif -#endif #else /* _WIN32 */ /* wants this for C++ */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include -#if !defined(SIZE_T_FMT) -#define SIZE_T_FMT "zu" -#endif #endif /* _WIN32 */ +#ifndef INT64_FMT #define INT64_FMT PRId64 +#endif +#ifndef UINT64_FMT #define UINT64_FMT PRIu64 +#endif #ifndef va_copy #define va_copy(x, y) x = y @@ -5940,7 +5974,7 @@ static int b64rev(int c) { } } -static uint8_t hexdec(const char *s) { +static unsigned char hexdec(const char *s) { #define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W') int a = tolower(*(const unsigned char *) s); int b = tolower(*(const unsigned char *) (s + 1)); @@ -6004,7 +6038,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { skip += 2; } else if (fmt[1] == 'z' && fmt[2] == 'u') { size_t val = va_arg(ap, size_t); - snprintf(buf, sizeof(buf), "%" SIZE_T_FMT, val); + snprintf(buf, sizeof(buf), "%lu", (unsigned long) val); len += out->printer(out, buf, strlen(buf)); skip += 1; } else if (fmt[1] == 'M') { @@ -6064,29 +6098,47 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { */ const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789"; - size_t n = strspn(fmt + 1, end_of_format_specifier); + int n = strspn(fmt + 1, end_of_format_specifier); char *pbuf = buf; - size_t need_len; + int need_len, size = sizeof(buf); char fmt2[20]; - va_list sub_ap; - strncpy(fmt2, fmt, n + 1 > sizeof(fmt2) ? sizeof(fmt2) : n + 1); + va_list ap_copy; + strncpy(fmt2, fmt, + n + 1 > (int) sizeof(fmt2) ? sizeof(fmt2) : (size_t) n + 1); fmt2[n + 1] = '\0'; - va_copy(sub_ap, ap); - need_len = - vsnprintf(buf, sizeof(buf), fmt2, sub_ap) + 1 /* null-term */; - /* - * TODO(lsm): Fix windows & eCos code path here. Their vsnprintf - * implementation returns -1 on overflow rather needed size. - */ - if (need_len > sizeof(buf)) { + va_copy(ap_copy, ap); + need_len = vsnprintf(pbuf, size, fmt2, ap_copy); + va_end(ap_copy); + + if (need_len < 0) { + /* + * Windows & eCos vsnprintf implementation return -1 on overflow + * instead of needed size. + */ + pbuf = NULL; + while (need_len < 0) { + free(pbuf); + size *= 2; + if ((pbuf = (char *) malloc(size)) == NULL) break; + va_copy(ap_copy, ap); + need_len = vsnprintf(pbuf, size, fmt2, ap_copy); + va_end(ap_copy); + } + } else if (need_len >= (int) sizeof(buf)) { /* * resulting string doesn't fit into a stack-allocated buffer `buf`, * so we need to allocate a new buffer from heap and use it */ - pbuf = (char *) malloc(need_len); - va_copy(sub_ap, ap); - vsnprintf(pbuf, need_len, fmt2, sub_ap); + if ((pbuf = (char *) malloc(need_len + 1)) != NULL) { + va_copy(ap_copy, ap); + vsnprintf(pbuf, need_len + 1, fmt2, ap_copy); + va_end(ap_copy); + } + } + if (pbuf == NULL) { + buf[0] = '\0'; + pbuf = buf; } /* @@ -6453,7 +6505,7 @@ int json_scanf(const char *str, int len, const char *fmt, ...) { int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK; int json_vfprintf(const char *file_name, const char *fmt, va_list ap) { int res = -1; - FILE *fp = fopen(file_name, "w"); + FILE *fp = fopen(file_name, "wb"); if (fp != NULL) { struct json_out out = JSON_OUT_FILE(fp); res = json_vprintf(&out, fmt, ap); @@ -6701,13 +6753,13 @@ int json_prettify_file(const char *file_name) { int res = -1; char *s = json_fread(file_name); FILE *fp; - if (s != NULL && (fp = fopen(file_name, "w")) != NULL) { + if (s != NULL && (fp = fopen(file_name, "wb")) != NULL) { struct json_out out = JSON_OUT_FILE(fp); res = json_prettify(s, strlen(s), &out); if (res < 0) { /* On error, restore the old content */ fclose(fp); - fp = fopen(file_name, "w"); + fp = fopen(file_name, "wb"); fseek(fp, 0, SEEK_SET); fwrite(s, 1, strlen(s), fp); } else { @@ -7622,18 +7674,18 @@ MJS_PRIVATE void emit_byte(struct pstate *pstate, uint8_t byte) { } MJS_PRIVATE void emit_int(struct pstate *pstate, int64_t n) { - add_lineno_map_item(pstate); struct mbuf *b = &pstate->mjs->bcode_gen; size_t llen = cs_varint_llen(n); + add_lineno_map_item(pstate); mbuf_insert(b, pstate->cur_idx, NULL, llen); cs_varint_encode(n, (uint8_t *) b->buf + pstate->cur_idx); pstate->cur_idx += llen; } MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len) { - add_lineno_map_item(pstate); struct mbuf *b = &pstate->mjs->bcode_gen; size_t llen = cs_varint_llen(len); + add_lineno_map_item(pstate); mbuf_insert(b, pstate->cur_idx, NULL, llen + len); cs_varint_encode(len, (uint8_t *) b->buf + pstate->cur_idx); memcpy(b->buf + pstate->cur_idx + llen, ptr, len); @@ -7642,9 +7694,9 @@ MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len) { MJS_PRIVATE int mjs_bcode_insert_offset(struct pstate *p, struct mjs *mjs, size_t offset, size_t v) { - assert(offset < mjs->bcode_gen.len); int llen = cs_varint_llen(v); int diff = llen - MJS_INIT_OFFSET_SIZE; + assert(offset < mjs->bcode_gen.len); if (diff > 0) { mbuf_resize(&mjs->bcode_gen, mjs->bcode_gen.size + diff); } @@ -7787,6 +7839,7 @@ static void mjs_load(struct mjs *mjs) { if (mjs_is_string(arg0)) { const char *path = mjs_get_cstring(mjs, &arg0); struct mjs_bcode_part *bp = NULL; + mjs_err_t ret; mjs_val_t *bottom = vptr(&mjs->scopes, 0), global = *bottom; mjs_own(mjs, &global); @@ -7795,7 +7848,6 @@ static void mjs_load(struct mjs *mjs) { custom_global = 1; *bottom = arg1; } - mjs_err_t ret; bp = mjs_get_loaded_file_bcode(mjs, path); if (bp == NULL) { /* File was not loaded before, so, load */ @@ -8047,6 +8099,7 @@ void mjs_destroy(struct mjs *mjs) { } struct mjs *mjs_create(void) { + mjs_val_t global_object; struct mjs *mjs = calloc(1, sizeof(*mjs)); mbuf_init(&mjs->stack, 0); mbuf_init(&mjs->call_stack, 0); @@ -8079,7 +8132,7 @@ struct mjs *mjs_create(void) { MJS_FUNC_FFI_ARENA_SIZE, MJS_FUNC_FFI_ARENA_INC_SIZE); mjs->ffi_sig_arena.destructor = mjs_ffi_sig_destructor; - mjs_val_t global_object = mjs_mk_object(mjs); + global_object = mjs_mk_object(mjs); mjs_init_builtin(mjs, global_object); mjs_set_ffi_resolver(mjs, dlsym); push_mjs_val(&mjs->scopes, global_object); @@ -8104,14 +8157,14 @@ mjs_err_t mjs_set_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...) { mjs_err_t mjs_prepend_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...) { + char *old_error_msg = mjs->error_msg; + char *new_error_msg = NULL; va_list ap; va_start(ap, fmt); /* err should never be MJS_OK here */ assert(err != MJS_OK); - char *old_error_msg = mjs->error_msg; - char *new_error_msg = NULL; mjs->error_msg = NULL; /* set error if only it wasn't already set to some error */ if (mjs->error == MJS_OK) { @@ -8372,7 +8425,7 @@ void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc) { /* Amalgamated: #include "mjs/src/mjs_util.h" */ void *mjs_mem_to_ptr(unsigned val) { - return (void *) (unsigned long) val; + return (void *) (uintptr_t) val; } void *mjs_mem_get_ptr(void *base, int offset) { @@ -8485,9 +8538,9 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, push_mjs_val(&mjs->call_stack, mjs->vals.this_obj); mjs->vals.this_obj = this_obj; - push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, offset)); + push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) offset)); push_mjs_val(&mjs->call_stack, - mjs_mk_number(mjs, mjs_stack_size(&mjs->scopes))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); push_mjs_val(&mjs->call_stack, retval_stack_idx); } @@ -8542,20 +8595,20 @@ static double do_arith_op(double da, double db, int op) { return da / db; } else { /* TODO(dfrank): add support for Infinity and return it here */ - return MJS_TAG_NAN; + return (double) MJS_TAG_NAN; } case TOK_REM: if (db != 0) { - return (int64_t) da % (int64_t) db; + return (double) ((int64_t) da % (int64_t) db); } else { - return MJS_TAG_NAN; + return (double) MJS_TAG_NAN; } - case TOK_AND: return (int64_t) da & (int64_t) db; - case TOK_OR: return (int64_t) da | (int64_t) db; - case TOK_XOR: return (int64_t) da ^ (int64_t) db; - case TOK_LSHIFT: return (int64_t) da << (int64_t) db; - case TOK_RSHIFT: return (int64_t) da >> (int64_t) db; - case TOK_URSHIFT: return (uint32_t) da >> (uint32_t) db; + case TOK_AND: return (double) ((int64_t) da & (int64_t) db); + case TOK_OR: return (double) ((int64_t) da | (int64_t) db); + case TOK_XOR: return (double) ((int64_t) da ^ (int64_t) db); + case TOK_LSHIFT: return (double) ((int64_t) da << (int64_t) db); + case TOK_RSHIFT: return (double) ((int64_t) da >> (int64_t) db); + case TOK_URSHIFT: return (double) ((uint32_t) da >> (uint32_t) db); } /* clang-format on */ return (int64_t) MJS_TAG_NAN; @@ -8571,6 +8624,7 @@ static mjs_val_t do_op(struct mjs *mjs, mjs_val_t a, mjs_val_t b, int op) { if ((mjs_is_foreign(a) || mjs_is_number(a)) && (mjs_is_foreign(b) || mjs_is_number(b))) { int is_result_ptr = 0; + double da, db, result; if (mjs_is_foreign(a) && mjs_is_foreign(b)) { /* When two operands are pointers, only subtraction is supported */ @@ -8587,13 +8641,11 @@ static mjs_val_t do_op(struct mjs *mjs, mjs_val_t a, mjs_val_t b, int op) { } is_result_ptr = 1; } - - double da, db; da = mjs_is_number(a) ? mjs_get_double(mjs, a) : (double) (uintptr_t) mjs_get_ptr(mjs, a); db = mjs_is_number(b) ? mjs_get_double(mjs, b) : (double) (uintptr_t) mjs_get_ptr(mjs, b); - double result = do_arith_op(da, db, op); + result = do_arith_op(da, db, op); /* * If at least one of the operands was a pointer, result should also be @@ -8678,7 +8730,7 @@ static void exec_expr(struct mjs *mjs, int op) { } case TOK_TILDA: { double a = mjs_get_double(mjs, mjs_pop(mjs)); - mjs_push(mjs, mjs_mk_number(mjs, ~(int64_t) a)); + mjs_push(mjs, mjs_mk_number(mjs, (double) (~(int64_t) a))); break; } case TOK_UNARY_PLUS: @@ -8848,7 +8900,7 @@ static int getprop_builtin_string(struct mjs *mjs, mjs_val_t val, if (strcmp(name, "length") == 0) { size_t val_len; mjs_get_string(mjs, &val, &val_len); - *res = mjs_mk_number(mjs, val_len); + *res = mjs_mk_number(mjs, (double) val_len); return 1; } else if (strcmp(name, "slice") == 0) { @@ -8933,11 +8985,6 @@ static int getprop_builtin(struct mjs *mjs, mjs_val_t val, mjs_val_t name, MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { size_t i; - - mjs_set_errorf(mjs, MJS_OK, NULL); - free(mjs->stack_trace); - mjs->stack_trace = NULL; - uint8_t prev_opcode = OP_MAX; uint8_t opcode = OP_MAX; @@ -8949,8 +8996,14 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int arg_stack_len = mjs->arg_stack.len; int scopes_len = mjs->scopes.len; size_t start_off = off; + const uint8_t *code; struct mjs_bcode_part bp = *mjs_bcode_part_get_by_offset(mjs, off); + + mjs_set_errorf(mjs, MJS_OK, NULL); + free(mjs->stack_trace); + mjs->stack_trace = NULL; + off -= bp.start_idx; for (i = off; i < bp.data.len; i++) { @@ -8965,7 +9018,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { maybe_gc(mjs); #endif - const uint8_t *code = (const uint8_t *) bp.data.p; + code = (const uint8_t *) bp.data.p; mjs_disasm_single(code, i); prev_opcode = opcode; opcode = code[i]; @@ -9114,7 +9167,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { case OP_PUSH_INT: { int llen; int64_t n = cs_varint_decode(&code[i + 1], &llen); - mjs_push(mjs, mjs_mk_number(mjs, n)); + mjs_push(mjs, mjs_mk_number(mjs, (double) n)); i += llen; break; } @@ -9180,27 +9233,30 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { * properly */ push_mjs_val(&mjs->arg_stack, - mjs_mk_number(mjs, mjs_stack_size(&mjs->stack))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack))); break; } case OP_CALL: { // LOG(LL_INFO, ("BEFORE CALL")); // mjs_dump(mjs, 0, stdout); + int func_pos; + mjs_val_t *func; mjs_val_t retval_stack_idx = vtop(&mjs->arg_stack); - int func_pos = mjs_get_int(mjs, retval_stack_idx) - 1; - mjs_val_t *func = vptr(&mjs->stack, func_pos); + func_pos = mjs_get_int(mjs, retval_stack_idx) - 1; + func = vptr(&mjs->stack, func_pos); /* Drop data stack size (pushed by OP_ARGS) */ mjs_pop_val(&mjs->arg_stack); if (mjs_is_function(*func)) { + size_t off_call; call_stack_push_frame(mjs, bp.start_idx + i, retval_stack_idx); /* * Function offset is a global bcode offset, so we need to convert it * to the local offset */ - size_t off_call = mjs_get_func_addr(*func) - 1; + off_call = mjs_get_func_addr(*func) - 1; bp = *mjs_bcode_part_get_by_offset(mjs, off_call); code = (const uint8_t *) bp.data.p; i = off_call - bp.start_idx; @@ -9232,11 +9288,11 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { } case OP_SET_ARG: { int llen1, llen2, n, arg_no = cs_varint_decode(&code[i + 1], &llen1); + mjs_val_t obj, key, v; n = cs_varint_decode(&code[i + llen1 + 1], &llen2); - mjs_val_t key = - mjs_mk_string(mjs, (char *) code + i + 1 + llen1 + llen2, n, 1); - mjs_val_t obj = vtop(&mjs->scopes); - mjs_val_t v = mjs_arg(mjs, arg_no); + key = mjs_mk_string(mjs, (char *) code + i + 1 + llen1 + llen2, n, 1); + obj = vtop(&mjs->scopes); + v = mjs_arg(mjs, arg_no); mjs_set_v(mjs, obj, key, v); i += llen1 + llen2 + n; break; @@ -9277,16 +9333,18 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int l1, l2, off = cs_varint_decode(&code[i + 1], &l1); /* push scope index */ push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, mjs_stack_size(&mjs->scopes))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); /* push break offset */ - push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, i + 1 /* OP_LOOP */ + l1 + off)); + push_mjs_val( + &mjs->loop_addresses, + mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP */ + l1 + off))); off = cs_varint_decode(&code[i + 1 + l1], &l2); /* push continue offset */ - push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, i + 1 /* OP_LOOP*/ + l1 + l2 + off)); + push_mjs_val( + &mjs->loop_addresses, + mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP*/ + l1 + l2 + off))); i += l1 + l2; break; } @@ -9300,6 +9358,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; } break; case OP_BREAK: { + size_t scopes_len; /* drop "continue" address */ mjs_pop_val(&mjs->loop_addresses); @@ -9307,7 +9366,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; /* restore scope index */ - size_t scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); + scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); assert(mjs_stack_size(&mjs->scopes) >= scopes_len); mjs->scopes.len = scopes_len * sizeof(mjs_val_t); @@ -9462,11 +9521,12 @@ mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, va_list ap; int i; mjs_err_t ret; - va_start(ap, nargs); mjs_val_t *args = calloc(1, sizeof(mjs_val_t) * nargs); + va_start(ap, nargs); for (i = 0; i < nargs; i++) { args[i] = va_arg(ap, mjs_val_t); } + va_end(ap); ret = mjs_apply(mjs, res, func, this_val, nargs, args); /* @@ -9480,19 +9540,19 @@ mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args) { - mjs_val_t r; + mjs_val_t r, prev_this_val, retval_stack_idx; int i; size_t addr = mjs_get_func_addr(func); LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); - mjs_val_t prev_this_val = mjs->vals.this_obj; + prev_this_val = mjs->vals.this_obj; /* Push undefined which will be later replaced with the return value */ mjs_push(mjs, MJS_UNDEFINED); /* Remember index by which return value should be written */ - mjs_val_t retval_stack_idx = mjs_mk_number(mjs, mjs_stack_size(&mjs->stack)); + retval_stack_idx = mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack)); // Push all arguments for (i = 0; i < nargs; i++) { @@ -9606,6 +9666,7 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, sig_len = strlen(s); } + fflush(stdout); mjs_ffi_sig_init(sig); /* Parse return value type {{{ */ @@ -9622,6 +9683,7 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, } mjs_ffi_sig_set_val_type(sig, vtidx++, val_type); /* }}} */ + fflush(stdout); /* Parse function name (if any) {{{ */ /* @@ -9677,9 +9739,9 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, /* Parse all args {{{ */ while (*tmp_e && *tmp_e != ')') { - tmp_e = cur; int level = 0; /* nested parens level */ int is_fp = 0; /* set to 1 is current arg is a callback function ptr */ + tmp_e = cur; /* Advance tmp_e until the next arg separator */ while (*tmp_e && (level > 0 || (*tmp_e != ',' && *tmp_e != ')'))) { @@ -9794,11 +9856,12 @@ struct ffi_cb_data { static union ffi_cb_data_val ffi_cb_impl_generic(void *param, struct ffi_cb_data *data) { struct mjs_ffi_cb_args *cbargs = (struct mjs_ffi_cb_args *) param; - mjs_val_t res = MJS_UNDEFINED; + mjs_val_t *args, res = MJS_UNDEFINED; union ffi_cb_data_val ret; int i; struct mjs *mjs = cbargs->mjs; mjs_ffi_ctype_t return_ctype = MJS_FFI_CTYPE_NONE; + mjs_err_t err; memset(&ret, 0, sizeof(ret)); mjs_own(mjs, &res); @@ -9807,7 +9870,7 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, assert(cbargs->sig.args_cnt > 0); /* Create JS arguments */ - mjs_val_t *args = calloc(1, sizeof(mjs_val_t) * cbargs->sig.args_cnt); + args = calloc(1, sizeof(mjs_val_t) * cbargs->sig.args_cnt); for (i = 0; i < cbargs->sig.args_cnt; i++) { mjs_ffi_ctype_t val_type = cbargs->sig.val_types[i + 1 /* first val_type is return value type */]; @@ -9816,7 +9879,7 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, args[i] = cbargs->userdata; break; case MJS_FFI_CTYPE_INT: - args[i] = mjs_mk_number(mjs, data->args[i].w); + args[i] = mjs_mk_number(mjs, (double) data->args[i].w); break; case MJS_FFI_CTYPE_BOOL: args[i] = mjs_mk_boolean(mjs, !!data->args[i].w); @@ -9853,8 +9916,8 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, /* Call JS function */ LOG(LL_VERBOSE_DEBUG, ("calling JS callback void-void %d from C", mjs_get_int(mjs, cbargs->func))); - mjs_err_t err = mjs_apply(mjs, &res, cbargs->func, MJS_UNDEFINED, - cbargs->sig.args_cnt, args); + err = mjs_apply(mjs, &res, cbargs->func, MJS_UNDEFINED, cbargs->sig.args_cnt, + args); /* * cbargs might be invalidated by the callback (if it called ffi_cb_free), so * null it out @@ -10085,20 +10148,18 @@ MJS_PRIVATE struct mjs_ffi_sig *mjs_get_ffi_sig_struct(mjs_val_t v) { } MJS_PRIVATE mjs_val_t mjs_mk_ffi_sig(struct mjs *mjs) { - (void) mjs; - struct mjs_ffi_sig *psig = new_ffi_sig(mjs); mjs_ffi_sig_init(psig); return mjs_ffi_sig_to_value(psig); } MJS_PRIVATE void mjs_ffi_sig_destructor(struct mjs *mjs, void *psig) { - (void) mjs; mjs_ffi_sig_free((mjs_ffi_sig_t *) psig); + (void) mjs; } MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs) { - mjs_err_t rcode = MJS_OK; + mjs_err_t e = MJS_OK; const char *sig_str = NULL; mjs_val_t sig_str_v = mjs_arg(mjs, 0); mjs_val_t ret_v = MJS_UNDEFINED; @@ -10106,18 +10167,13 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs) { size_t sig_str_len; sig_str = mjs_get_string(mjs, &sig_str_v, &sig_str_len); - - rcode = - mjs_parse_ffi_signature(mjs, sig_str, sig_str_len, psig, FFI_SIG_FUNC); - if (rcode != MJS_OK) { - goto clean; - } - + e = mjs_parse_ffi_signature(mjs, sig_str, sig_str_len, psig, FFI_SIG_FUNC); + if (e != MJS_OK) goto clean; ret_v = mjs_ffi_sig_to_value(psig); clean: mjs_return(mjs, ret_v); - return rcode; + return e; } MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { @@ -10598,7 +10654,13 @@ MJS_PRIVATE int mjs_ffi_is_regular_word_or_void(mjs_ffi_ctype_t type) { #ifdef _WIN32 void *dlsym(void *handle, const char *name) { - return GetProcAddress(GetModuleHandle(NULL), name); + static HANDLE msvcrt_dll; + void *sym = NULL; + if (msvcrt_dll == NULL) msvcrt_dll = GetModuleHandle("msvcrt.dll"); + if ((sym = GetProcAddress(GetModuleHandle(NULL), name)) == NULL) { + sym = GetProcAddress(msvcrt_dll, name); + } + return sym; } #elif !defined(__unix__) && !defined(__APPLE__) void *dlsym(void *handle, const char *name) { @@ -12059,39 +12121,40 @@ static int findtok(int *toks, int tok) { static void emit_op(struct pstate *pstate, int tok) { assert(tok >= 0 && tok <= 255); emit_byte(pstate, OP_EXPR); - emit_byte(pstate, tok); + emit_byte(pstate, (uint8_t) tok); } // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. -#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ - do { \ - mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ - if (prev_op != TOK_EOF) emit_op(p, prev_op); \ - if (findtok(ops, p->tok.tok) != TOK_EOF) { \ - int op = p->tok.tok; \ - size_t off_if = 0; \ - /* For AND/OR, implement short-circuit evaluation */ \ - if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ - emit_byte(p, ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ - : OP_JMP_NEUTRAL_TRUE); \ - off_if = p->cur_idx; \ - emit_init_offset(p); \ - /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ - /* Just drop the first value, and evaluate the second one. */ \ - emit_byte(p, OP_DROP); \ - op = TOK_EOF; \ - } \ - pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ - \ - if (off_if != 0) { \ - mjs_bcode_insert_offset(p, p->mjs, off_if, \ - p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ - } \ - } \ - return res; \ +#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ + do { \ + mjs_err_t res = MJS_OK; \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + if (prev_op != TOK_EOF) emit_op(p, prev_op); \ + if (findtok(ops, p->tok.tok) != TOK_EOF) { \ + int op = p->tok.tok; \ + size_t off_if = 0; \ + /* For AND/OR, implement short-circuit evaluation */ \ + if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ + emit_byte(p, \ + (uint8_t)(ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ + : OP_JMP_NEUTRAL_TRUE)); \ + off_if = p->cur_idx; \ + emit_init_offset(p); \ + /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ + /* Just drop the first value, and evaluate the second one. */ \ + emit_byte(p, (uint8_t) OP_DROP); \ + op = TOK_EOF; \ + } \ + pnext1(p); \ + if ((res = f2(p, op)) != MJS_OK) return res; \ + \ + if (off_if != 0) { \ + mjs_bcode_insert_offset(p, p->mjs, off_if, \ + p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ + } \ + } \ + return res; \ } while (0) #define PARSE_RTL_BINOP(p, f1, f2, ops, prev_op) \ @@ -12258,7 +12321,7 @@ static enum mjs_err parse_literal(struct pstate *p, const struct tok *t) { int next_tok = ptest(p); emit_byte(p, OP_PUSH_STR); emit_str(p, t->ptr, t->len); - emit_byte(p, prev_tok == TOK_DOT ? OP_SWAP : OP_FIND_SCOPE); + emit_byte(p, (uint8_t)(prev_tok == TOK_DOT ? OP_SWAP : OP_FIND_SCOPE)); if (!findtok(s_assign_ops, next_tok) && !findtok(s_postfix_ops, next_tok) && /* TODO(dfrank): fix: it doesn't work for prefix ops */ @@ -12281,8 +12344,9 @@ static enum mjs_err parse_literal(struct pstate *p, const struct tok *t) { break; } case TOK_STR: { + size_t oldlen; emit_byte(p, OP_PUSH_STR); - size_t oldlen = bcode_gen->len; + oldlen = bcode_gen->len; embed_string(bcode_gen, p->cur_idx, t->ptr, t->len, EMBSTR_UNESCAPE); p->cur_idx += bcode_gen->len - oldlen; } break; @@ -12594,6 +12658,9 @@ static int check_for_in(struct pstate *p) { static mjs_err_t parse_for(struct pstate *p) { mjs_err_t res = MJS_OK; + size_t off_b, off_c, off_init_end; + size_t off_incr_begin, off_cond_begin, off_cond_end; + int buf_cur_idx; LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr)); EXPECT(p, TOK_KEYWORD_FOR); @@ -12624,9 +12691,9 @@ static mjs_err_t parse_for(struct pstate *p) { /* Before parsing condition statement, push break/continue offsets */ emit_byte(p, OP_LOOP); - size_t off_b = p->cur_idx; + off_b = p->cur_idx; emit_init_offset(p); - size_t off_c = p->cur_idx; + off_c = p->cur_idx; emit_init_offset(p); /* Parse init statement */ @@ -12639,11 +12706,11 @@ static mjs_err_t parse_for(struct pstate *p) { emit_byte(p, OP_DROP); emit_byte(p, OP_JMP); - size_t off_init_end = p->cur_idx; + off_init_end = p->cur_idx; emit_init_offset(p); - size_t off_incr_begin = p->cur_idx; - size_t off_cond_begin = p->cur_idx; + off_incr_begin = p->cur_idx; + off_cond_begin = p->cur_idx; /* Parse cond statement */ if ((res = parse_expr(p)) != MJS_OK) return res; @@ -12651,7 +12718,7 @@ static mjs_err_t parse_for(struct pstate *p) { /* Parse incr statement */ /* Incr statement should be placed before cond, so, adjust cur_idx */ - int buf_cur_idx = p->cur_idx; + buf_cur_idx = p->cur_idx; p->cur_idx = off_incr_begin; if ((res = parse_expr(p)) != MJS_OK) return res; @@ -12671,7 +12738,7 @@ static mjs_err_t parse_for(struct pstate *p) { /* p->cur_idx is now at the end of "cond" */ /* Exit the loop if false */ emit_byte(p, OP_JMP_FALSE); - size_t off_cond_end = p->cur_idx; + off_cond_end = p->cur_idx; emit_init_offset(p); /* Parse loop body */ @@ -12894,6 +12961,10 @@ MJS_PRIVATE mjs_err_t mjs_parse(const char *path, const char *buf, struct mjs *mjs) { mjs_err_t res = MJS_OK; struct pstate p; + size_t start_idx, llen; + int map_len; + mjs_header_item_t bcode_offset, map_offset, total_size; + pinit(path, buf, &p); p.mjs = mjs; p.cur_idx = p.mjs->bcode_gen.len; @@ -12905,14 +12976,14 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { */ /* Remember starting bcode position, and reserve the room for bcode header */ - size_t start_idx = p.mjs->bcode_gen.len; + start_idx = p.mjs->bcode_gen.len; mbuf_append(&p.mjs->bcode_gen, NULL, sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT); /* Append NULL-terminated filename */ mbuf_append(&p.mjs->bcode_gen, path, strlen(path) + 1 /* null-terminate */); - mjs_header_item_t bcode_offset = p.mjs->bcode_gen.len - start_idx; + bcode_offset = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET, &bcode_offset, sizeof(mjs_header_item_t)); @@ -12924,14 +12995,14 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { emit_byte(&p, OP_EXIT); /* remember map offset */ - mjs_header_item_t map_offset = p.mjs->bcode_gen.len - start_idx; + map_offset = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET, &map_offset, sizeof(mjs_header_item_t)); /* put map length varint */ - int map_len = p.offset_lineno_map.len; - size_t llen = cs_varint_llen(map_len); + map_len = p.offset_lineno_map.len; + llen = cs_varint_llen(map_len); mbuf_resize(&p.mjs->bcode_gen, p.mjs->bcode_gen.size + llen); cs_varint_encode(map_len, (uint8_t *) p.mjs->bcode_gen.buf + p.mjs->bcode_gen.len); @@ -12941,7 +13012,7 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { mbuf_append(&p.mjs->bcode_gen, p.offset_lineno_map.buf, p.offset_lineno_map.len); - mjs_header_item_t total_size = p.mjs->bcode_gen.len - start_idx; + total_size = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_TOTAL_SIZE, &total_size, sizeof(mjs_header_item_t)); @@ -13159,6 +13230,8 @@ int mjs_is_string(mjs_val_t v) { } mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { + struct mbuf *m; + mjs_val_t offset, tag = MJS_TAG_STRING_F; if (len == 0) { /* * Zero length for foreign string has a special meaning (that the foreign @@ -13168,8 +13241,8 @@ mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { */ copy = 1; } - struct mbuf *m = copy ? &mjs->owned_strings : &mjs->foreign_strings; - mjs_val_t offset = m->len, tag = MJS_TAG_STRING_F; + m = copy ? &mjs->owned_strings : &mjs->foreign_strings; + offset = m->len; if (len == ~((size_t) 0)) len = strlen(p); @@ -13285,7 +13358,7 @@ const char *mjs_get_string(struct mjs *mjs, mjs_val_t *v, size_t *sizep) { char *s = mjs->foreign_strings.buf + offset; size = cs_varint_decode((uint8_t *) s, &llen); - memcpy(&p, s + llen, sizeof(p)); + memcpy((char **) &p, s + llen, sizeof(p)); } } else { assert(0); @@ -13966,7 +14039,7 @@ void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { json_printf(out, "%s", ""); } else if (mjs_is_foreign(v)) { json_printf(out, "%s%lx%s", ""); + (unsigned long) (uintptr_t) mjs_get_ptr(mjs, v), ">"); } else if (mjs_is_function(v)) { json_printf(out, "%s%d%s", ""); } else if (mjs_is_null(v)) { @@ -14133,6 +14206,9 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i) { i += strlen((char *) (code + i + 1)) + 1; break; } + default: + LOG(LL_VERBOSE_DEBUG, ("%s", buf)); + break; } return i - start_i; } @@ -14195,6 +14271,7 @@ MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, const char *arg_name, enum mjs_type expected_type, mjs_val_t *parg) { mjs_val_t arg = MJS_UNDEFINED; + enum mjs_type actual_type; if (arg_num >= 0) { int nargs = mjs_nargs(mjs); @@ -14209,7 +14286,7 @@ MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, arg = mjs->vals.this_obj; } - enum mjs_type actual_type = mjs_get_type(arg); + actual_type = mjs_get_type(arg); if (actual_type != expected_type) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "%s should be a %s, %s given", arg_name, mjs_stringify_type(expected_type), @@ -14254,15 +14331,15 @@ const char *mjs_get_bcode_filename_by_offset(struct mjs *mjs, int offset) { } int mjs_get_lineno_by_offset(struct mjs *mjs, int offset) { - int ret = 1; + int llen, map_len, prev_line_no, ret = 1; struct mjs_bcode_part *bp = mjs_bcode_part_get_by_offset(mjs, offset); + uint8_t *p, *pe; if (bp != NULL) { - mjs_header_item_t map_offset; + mjs_header_item_t map_offset, bcode_offset; memcpy(&map_offset, bp->data.p + 1 /* OP_BCODE_HEADER */ + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET, sizeof(map_offset)); - mjs_header_item_t bcode_offset; memcpy(&bcode_offset, bp->data.p + 1 /* OP_BCODE_HEADER */ + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET, @@ -14271,18 +14348,17 @@ int mjs_get_lineno_by_offset(struct mjs *mjs, int offset) { offset -= (1 /* OP_BCODE_HEADER */ + bcode_offset) + bp->start_idx; /* get pointer to the length of the map followed by the map itself */ - uint8_t *p = (uint8_t *) bp->data.p + 1 /* OP_BCODE_HEADER */ + map_offset; + p = (uint8_t *) bp->data.p + 1 /* OP_BCODE_HEADER */ + map_offset; - int llen, map_len = cs_varint_decode(p, &llen); + map_len = cs_varint_decode(p, &llen); p += llen; - uint8_t *pe = p + map_len; + pe = p + map_len; - int prev_line_no = 1; + prev_line_no = 1; while (p < pe) { - int llen; - int cur_offset = cs_varint_decode(p, &llen); + int llen, line_no, cur_offset = cs_varint_decode(p, &llen); p += llen; - int line_no = cs_varint_decode(p, &llen); + line_no = cs_varint_decode(p, &llen); p += llen; if (cur_offset >= offset) { diff --git a/mjs.h b/mjs.h index 00ff906..430ee8f 100644 --- a/mjs.h +++ b/mjs.h @@ -65,7 +65,13 @@ #ifndef MJS_CORE_PUBLIC_H_ #define MJS_CORE_PUBLIC_H_ +#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include +#else +typedef unsigned __int64 uint64_t; +typedef int int32_t; +typedef unsigned char uint8_t; +#endif #include #include /* Amalgamated: #include "mjs/src/mjs_license.h" */ @@ -347,7 +353,13 @@ void mjs_array_del(struct mjs *mjs, mjs_val_t arr, unsigned long index); #ifndef MJS_CORE_PUBLIC_H_ #define MJS_CORE_PUBLIC_H_ +#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include +#else +typedef unsigned __int64 uint64_t; +typedef int int32_t; +typedef unsigned char uint8_t; +#endif #include #include /* Amalgamated: #include "mjs/src/mjs_license.h" */ diff --git a/mjs/Makefile b/mjs/Makefile index 0d018cc..d3fa3f0 100644 --- a/mjs/Makefile +++ b/mjs/Makefile @@ -3,6 +3,11 @@ SRCPATH = src VPATH = $(REPO_ROOT)/common $(REPO_ROOT)/frozen src BUILD_DIR = build +R ?= $(abspath $(REPO_ROOT)) +RD ?= docker run -v $(R):$(R) -w $(CURDIR) +DOCKER_GCC ?= $(RD) docker.cesanta.com/gcc +DOCKER_CLANG ?= $(RD) docker.cesanta.com/clang + include $(SRCPATH)/mjs_sources.mk TOP_SOURCES = $(addprefix $(SRCPATH)/, $(SOURCES)) @@ -12,8 +17,8 @@ TOP_HEADERS_DIRS = $(sort $(dir $(TOP_HEADERS))) MFLAGS += -I. -I$(REPO_ROOT) -Isrc MFLAGS += -DMJS_MAIN -DMJS_EXPOSE_PRIVATE -DCS_ENABLE_STDIO -DMJS_ENABLE_DEBUG -CFLAGS += -lm -W -Wall -g -CFLAGS += $(MFLAGS) $(CFLAGS_EXTRA) +MFLAGS += $(CFLAGS_EXTRA) +CFLAGS += -lm -W -Wall -g $(MFLAGS) COMMON_CFLAGS = -DCS_MMAP ASAN_CFLAGS = -fsanitize=address @@ -66,7 +71,7 @@ CFLAGS += $(COMMON_CFLAGS) # NOTE: we compile straight from sources, not from the single amalgamated file, # in order to make sure that all sources include the right headers $(PROG): $(TOP_SOURCES) $(TOP_HEADERS) $(BUILD_DIR) - $(CLANG) $(CFLAGS) $(CPPFLAGS) $(TOP_SOURCES) -o $(PROG) + $(DOCKER_CLANG) $(CFLAGS) $(CPPFLAGS) $(TOP_SOURCES) -o $(PROG) $(BUILD_DIR): mkdir -p $@ @@ -74,18 +79,6 @@ $(BUILD_DIR): $(BUILD_DIR)/%.o: %.c $(TOP_HEADERS) $(CLANG) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< -# On Windows and Mac, run container as root since volume sharing on those OSes -# doesn't play nice with unprivileged user. -# -# On other OSes, run it as the current user. -DOCKER_USER_ARG = -ifneq ($(OS),Windows_NT) -UNAME_S := $(shell uname -s) -ifneq ($(UNAME_S),Darwin) -DOCKER_USER_ARG = --user $$(id -u):$$(id -u) -endif -endif - COMMON_TEST_FLAGS = -W -Wall -I. -I$(REPO_ROOT) -g3 -O0 $(COMMON_CFLAGS) $< $(TESTUTIL_FILES) -DMJS_MEMORY_STATS include $(REPO_ROOT)/common.mk @@ -132,12 +125,14 @@ TEST_VARIANTS = # params: # # 1: binary name component, e.g. "clang_O1_offset_4_whatever_else" -# 2: compiler, like "clang" or "gcc" -# 3: compiler flags +# 2: docker image to run compiler and binary in +# 3: full path to compiler, like "/usr/bin/clang-3.6" or "/usr/bin/gcc" +# 4: compiler flags define compile_test $(BUILD_DIR)/unit_test_$1: tests/unit_test.c mjs.c $(TESTUTIL_FILES) $(BUILD_DIR) - @echo BUILDING $$@ with $2, flags: "'$3'" - $2 $$(COMMON_TEST_FLAGS) $3 -lm -o $$@ + @echo BUILDING $$@ with $2[$3], flags: "'$4'" + $(RD) --entrypoint $3 $2 $$(COMMON_TEST_FLAGS) $4 -lm -o $$@ + $(RD) --entrypoint ./$$@ $2 TEST_VARIANTS += $(BUILD_DIR)/unit_test_$1 endef @@ -147,7 +142,7 @@ endef # 2: binary name component, typically the same as compiler: "clang" or "gcc" # 3: additional compiler flags define compile_test_with_compiler -$(eval $(call compile_test,$2,$1,$3)) +$(eval $(call compile_test,$3,$1,$2,$4)) endef # params: @@ -155,9 +150,9 @@ endef # 2: binary name component, like "O0" or whatever # 3: additional compiler flags define compile_test_with_opt -$(eval $(call compile_test_with_compiler,$(CLANG),clang_$2,$(ASAN_CFLAGS) $1 $3)) -$(eval $(call compile_test_with_compiler,$(CLANG),clang_32bit_$2,-m32 $1 $3)) -$(eval $(call compile_test_with_compiler,gcc,gcc_$2,$1 $3)) +$(eval $(call compile_test_with_compiler,docker.cesanta.com/gcc,/usr/bin/gcc,gcc_$2,$1 $3)) +$(eval $(call compile_test_with_compiler,docker.cesanta.com/clang,/usr/bin/clang-3.6,clang_$2,$(ASAN_CFLAGS) $1 $3)) +$(eval $(call compile_test_with_compiler,docker.cesanta.com/clang,/usr/bin/clang-3.6,clang_32bit_$2,-m32 $1 $3)) endef # params: @@ -191,17 +186,17 @@ $(eval $(call compile_test_all)) # Run all tests from $(TEST_VARIANTS) test_full: $(TEST_VARIANTS) $(PROG) - for f in $(TEST_VARIANTS); do \ - echo ; echo running $$f; \ - $$f; \ - done +# for f in $(TEST_VARIANTS); do \ +# echo ; echo running $$f; \ +# $$f; \ +# done # Run just a single test (a first one from $(TEST_VARIANTS)) test: $(firstword $(TEST_VARIANTS)) - $< +# $< clean: - rm -rf $(BUILD_DIR) *.obj mjs.c mjs.h + rm -rf $(BUILD_DIR) *.obj mjs.c mjs.h _CL_* print_sources: @echo $(TOP_SOURCES) $(TOP_HEADERS) @@ -209,19 +204,22 @@ print_sources: print_source_dirs: @echo $(TOP_SOURCES_DIRS) $(TOP_HEADERS_DIRS) -################################### Windows targets for wine, with MSVC6 - -$(PROG).exe: $(BUILD_DIR) $(TOP_HEADERS) mjs.c - wine cl $(MFLAGS) mjs.c -O1 -MD /Fe$@ - -$(BUILD_DIR)/unit_test.exe: tests/unit_test.c mjs.c $(TESTUTIL_FILES) $(BUILD_DIR) - wine cl -I. -I$(REPO_ROOT) $< $(TESTUTIL_FILES) -o $@ - -wtest: $(BUILD_DIR)/unit_test.exe - wine $(BUILD_DIR)/unit_test.exe - difftest: @TMP=`mktemp -t checkout-diff.XXXXXX`; \ git diff >$$TMP ; \ if [ -s "$$TMP" ]; then echo found diffs in checkout:; git status -s; head -n 50 "$$TMP"; exit 1; fi; \ rm $$TMP + +################################### Windows targets for wine, with MSVC6 + +ci-test: $(BUILD_DIR) vc98 vc2017 test_full + +$(PROG).exe: $(BUILD_DIR) $(TOP_HEADERS) mjs.c + $(RD) docker.cesanta.com/vc98 wine cl mjs.c $(CLFLAGS) $(MFLAGS) /Fe$@ + +TEST_SOURCES = tests/unit_test.c $(TESTUTIL_FILES) +CLFLAGS = /DWIN32_LEAN_AND_MEAN /MD /O1 /TC /W2 /WX /I.. /I. /DNDEBUG /DMJS_MEMORY_STATS +vc98 vc2017: mjs.c mjs.h + $(RD) docker.cesanta.com/$@ wine cl $(TEST_SOURCES) $(CLFLAGS) /Fe$@.exe + $(RD) docker.cesanta.com/$@ wine ./$@.exe + diff --git a/mjs/src/ffi/ffi.h b/mjs/src/ffi/ffi.h index 7e46210..25ca466 100644 --- a/mjs/src/ffi/ffi.h +++ b/mjs/src/ffi/ffi.h @@ -6,7 +6,6 @@ #ifndef MJS_FFI_FFI_H_ #define MJS_FFI_FFI_H_ -#include #include "common/platform.h" #if defined(__cplusplus) diff --git a/mjs/src/mjs_bcode.c b/mjs/src/mjs_bcode.c index fa733dc..b286bde 100644 --- a/mjs/src/mjs_bcode.c +++ b/mjs/src/mjs_bcode.c @@ -40,18 +40,18 @@ MJS_PRIVATE void emit_byte(struct pstate *pstate, uint8_t byte) { } MJS_PRIVATE void emit_int(struct pstate *pstate, int64_t n) { - add_lineno_map_item(pstate); struct mbuf *b = &pstate->mjs->bcode_gen; size_t llen = cs_varint_llen(n); + add_lineno_map_item(pstate); mbuf_insert(b, pstate->cur_idx, NULL, llen); cs_varint_encode(n, (uint8_t *) b->buf + pstate->cur_idx); pstate->cur_idx += llen; } MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len) { - add_lineno_map_item(pstate); struct mbuf *b = &pstate->mjs->bcode_gen; size_t llen = cs_varint_llen(len); + add_lineno_map_item(pstate); mbuf_insert(b, pstate->cur_idx, NULL, llen + len); cs_varint_encode(len, (uint8_t *) b->buf + pstate->cur_idx); memcpy(b->buf + pstate->cur_idx + llen, ptr, len); @@ -60,9 +60,9 @@ MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len) { MJS_PRIVATE int mjs_bcode_insert_offset(struct pstate *p, struct mjs *mjs, size_t offset, size_t v) { - assert(offset < mjs->bcode_gen.len); int llen = cs_varint_llen(v); int diff = llen - MJS_INIT_OFFSET_SIZE; + assert(offset < mjs->bcode_gen.len); if (diff > 0) { mbuf_resize(&mjs->bcode_gen, mjs->bcode_gen.size + diff); } diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index 45ded8b..a5870bf 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -56,6 +56,7 @@ static void mjs_load(struct mjs *mjs) { if (mjs_is_string(arg0)) { const char *path = mjs_get_cstring(mjs, &arg0); struct mjs_bcode_part *bp = NULL; + mjs_err_t ret; mjs_val_t *bottom = vptr(&mjs->scopes, 0), global = *bottom; mjs_own(mjs, &global); @@ -64,7 +65,6 @@ static void mjs_load(struct mjs *mjs) { custom_global = 1; *bottom = arg1; } - mjs_err_t ret; bp = mjs_get_loaded_file_bcode(mjs, path); if (bp == NULL) { /* File was not loaded before, so, load */ diff --git a/mjs/src/mjs_core.c b/mjs/src/mjs_core.c index f058abe..d365c02 100644 --- a/mjs/src/mjs_core.c +++ b/mjs/src/mjs_core.c @@ -71,6 +71,7 @@ void mjs_destroy(struct mjs *mjs) { } struct mjs *mjs_create(void) { + mjs_val_t global_object; struct mjs *mjs = calloc(1, sizeof(*mjs)); mbuf_init(&mjs->stack, 0); mbuf_init(&mjs->call_stack, 0); @@ -103,7 +104,7 @@ struct mjs *mjs_create(void) { MJS_FUNC_FFI_ARENA_SIZE, MJS_FUNC_FFI_ARENA_INC_SIZE); mjs->ffi_sig_arena.destructor = mjs_ffi_sig_destructor; - mjs_val_t global_object = mjs_mk_object(mjs); + global_object = mjs_mk_object(mjs); mjs_init_builtin(mjs, global_object); mjs_set_ffi_resolver(mjs, dlsym); push_mjs_val(&mjs->scopes, global_object); @@ -128,14 +129,14 @@ mjs_err_t mjs_set_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...) { mjs_err_t mjs_prepend_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...) { + char *old_error_msg = mjs->error_msg; + char *new_error_msg = NULL; va_list ap; va_start(ap, fmt); /* err should never be MJS_OK here */ assert(err != MJS_OK); - char *old_error_msg = mjs->error_msg; - char *new_error_msg = NULL; mjs->error_msg = NULL; /* set error if only it wasn't already set to some error */ if (mjs->error == MJS_OK) { diff --git a/mjs/src/mjs_core_public.h b/mjs/src/mjs_core_public.h index b374fdd..be1675e 100644 --- a/mjs/src/mjs_core_public.h +++ b/mjs/src/mjs_core_public.h @@ -6,7 +6,13 @@ #ifndef MJS_CORE_PUBLIC_H_ #define MJS_CORE_PUBLIC_H_ +#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include +#else +typedef unsigned __int64 uint64_t; +typedef int int32_t; +typedef unsigned char uint8_t; +#endif #include #include #include "mjs/src/mjs_license.h" diff --git a/mjs/src/mjs_dataview.c b/mjs/src/mjs_dataview.c index 3902298..2b85ef8 100644 --- a/mjs/src/mjs_dataview.c +++ b/mjs/src/mjs_dataview.c @@ -10,7 +10,7 @@ #include "mjs/src/mjs_util.h" void *mjs_mem_to_ptr(unsigned val) { - return (void *) (unsigned long) val; + return (void *) (uintptr_t) val; } void *mjs_mem_get_ptr(void *base, int offset) { diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index d110613..d4d46d2 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -34,9 +34,9 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, push_mjs_val(&mjs->call_stack, mjs->vals.this_obj); mjs->vals.this_obj = this_obj; - push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, offset)); + push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) offset)); push_mjs_val(&mjs->call_stack, - mjs_mk_number(mjs, mjs_stack_size(&mjs->scopes))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); push_mjs_val(&mjs->call_stack, retval_stack_idx); } @@ -91,20 +91,20 @@ static double do_arith_op(double da, double db, int op) { return da / db; } else { /* TODO(dfrank): add support for Infinity and return it here */ - return MJS_TAG_NAN; + return (double) MJS_TAG_NAN; } case TOK_REM: if (db != 0) { - return (int64_t) da % (int64_t) db; + return (double) ((int64_t) da % (int64_t) db); } else { - return MJS_TAG_NAN; + return (double) MJS_TAG_NAN; } - case TOK_AND: return (int64_t) da & (int64_t) db; - case TOK_OR: return (int64_t) da | (int64_t) db; - case TOK_XOR: return (int64_t) da ^ (int64_t) db; - case TOK_LSHIFT: return (int64_t) da << (int64_t) db; - case TOK_RSHIFT: return (int64_t) da >> (int64_t) db; - case TOK_URSHIFT: return (uint32_t) da >> (uint32_t) db; + case TOK_AND: return (double) ((int64_t) da & (int64_t) db); + case TOK_OR: return (double) ((int64_t) da | (int64_t) db); + case TOK_XOR: return (double) ((int64_t) da ^ (int64_t) db); + case TOK_LSHIFT: return (double) ((int64_t) da << (int64_t) db); + case TOK_RSHIFT: return (double) ((int64_t) da >> (int64_t) db); + case TOK_URSHIFT: return (double) ((uint32_t) da >> (uint32_t) db); } /* clang-format on */ return (int64_t) MJS_TAG_NAN; @@ -120,6 +120,7 @@ static mjs_val_t do_op(struct mjs *mjs, mjs_val_t a, mjs_val_t b, int op) { if ((mjs_is_foreign(a) || mjs_is_number(a)) && (mjs_is_foreign(b) || mjs_is_number(b))) { int is_result_ptr = 0; + double da, db, result; if (mjs_is_foreign(a) && mjs_is_foreign(b)) { /* When two operands are pointers, only subtraction is supported */ @@ -136,13 +137,11 @@ static mjs_val_t do_op(struct mjs *mjs, mjs_val_t a, mjs_val_t b, int op) { } is_result_ptr = 1; } - - double da, db; da = mjs_is_number(a) ? mjs_get_double(mjs, a) : (double) (uintptr_t) mjs_get_ptr(mjs, a); db = mjs_is_number(b) ? mjs_get_double(mjs, b) : (double) (uintptr_t) mjs_get_ptr(mjs, b); - double result = do_arith_op(da, db, op); + result = do_arith_op(da, db, op); /* * If at least one of the operands was a pointer, result should also be @@ -227,7 +226,7 @@ static void exec_expr(struct mjs *mjs, int op) { } case TOK_TILDA: { double a = mjs_get_double(mjs, mjs_pop(mjs)); - mjs_push(mjs, mjs_mk_number(mjs, ~(int64_t) a)); + mjs_push(mjs, mjs_mk_number(mjs, (double) (~(int64_t) a))); break; } case TOK_UNARY_PLUS: @@ -397,7 +396,7 @@ static int getprop_builtin_string(struct mjs *mjs, mjs_val_t val, if (strcmp(name, "length") == 0) { size_t val_len; mjs_get_string(mjs, &val, &val_len); - *res = mjs_mk_number(mjs, val_len); + *res = mjs_mk_number(mjs, (double) val_len); return 1; } else if (strcmp(name, "slice") == 0) { @@ -482,11 +481,6 @@ static int getprop_builtin(struct mjs *mjs, mjs_val_t val, mjs_val_t name, MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { size_t i; - - mjs_set_errorf(mjs, MJS_OK, NULL); - free(mjs->stack_trace); - mjs->stack_trace = NULL; - uint8_t prev_opcode = OP_MAX; uint8_t opcode = OP_MAX; @@ -498,8 +492,14 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int arg_stack_len = mjs->arg_stack.len; int scopes_len = mjs->scopes.len; size_t start_off = off; + const uint8_t *code; struct mjs_bcode_part bp = *mjs_bcode_part_get_by_offset(mjs, off); + + mjs_set_errorf(mjs, MJS_OK, NULL); + free(mjs->stack_trace); + mjs->stack_trace = NULL; + off -= bp.start_idx; for (i = off; i < bp.data.len; i++) { @@ -514,7 +514,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { maybe_gc(mjs); #endif - const uint8_t *code = (const uint8_t *) bp.data.p; + code = (const uint8_t *) bp.data.p; mjs_disasm_single(code, i); prev_opcode = opcode; opcode = code[i]; @@ -663,7 +663,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { case OP_PUSH_INT: { int llen; int64_t n = cs_varint_decode(&code[i + 1], &llen); - mjs_push(mjs, mjs_mk_number(mjs, n)); + mjs_push(mjs, mjs_mk_number(mjs, (double) n)); i += llen; break; } @@ -729,27 +729,30 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { * properly */ push_mjs_val(&mjs->arg_stack, - mjs_mk_number(mjs, mjs_stack_size(&mjs->stack))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack))); break; } case OP_CALL: { // LOG(LL_INFO, ("BEFORE CALL")); // mjs_dump(mjs, 0, stdout); + int func_pos; + mjs_val_t *func; mjs_val_t retval_stack_idx = vtop(&mjs->arg_stack); - int func_pos = mjs_get_int(mjs, retval_stack_idx) - 1; - mjs_val_t *func = vptr(&mjs->stack, func_pos); + func_pos = mjs_get_int(mjs, retval_stack_idx) - 1; + func = vptr(&mjs->stack, func_pos); /* Drop data stack size (pushed by OP_ARGS) */ mjs_pop_val(&mjs->arg_stack); if (mjs_is_function(*func)) { + size_t off_call; call_stack_push_frame(mjs, bp.start_idx + i, retval_stack_idx); /* * Function offset is a global bcode offset, so we need to convert it * to the local offset */ - size_t off_call = mjs_get_func_addr(*func) - 1; + off_call = mjs_get_func_addr(*func) - 1; bp = *mjs_bcode_part_get_by_offset(mjs, off_call); code = (const uint8_t *) bp.data.p; i = off_call - bp.start_idx; @@ -781,11 +784,11 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { } case OP_SET_ARG: { int llen1, llen2, n, arg_no = cs_varint_decode(&code[i + 1], &llen1); + mjs_val_t obj, key, v; n = cs_varint_decode(&code[i + llen1 + 1], &llen2); - mjs_val_t key = - mjs_mk_string(mjs, (char *) code + i + 1 + llen1 + llen2, n, 1); - mjs_val_t obj = vtop(&mjs->scopes); - mjs_val_t v = mjs_arg(mjs, arg_no); + key = mjs_mk_string(mjs, (char *) code + i + 1 + llen1 + llen2, n, 1); + obj = vtop(&mjs->scopes); + v = mjs_arg(mjs, arg_no); mjs_set_v(mjs, obj, key, v); i += llen1 + llen2 + n; break; @@ -826,16 +829,18 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int l1, l2, off = cs_varint_decode(&code[i + 1], &l1); /* push scope index */ push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, mjs_stack_size(&mjs->scopes))); + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); /* push break offset */ - push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, i + 1 /* OP_LOOP */ + l1 + off)); + push_mjs_val( + &mjs->loop_addresses, + mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP */ + l1 + off))); off = cs_varint_decode(&code[i + 1 + l1], &l2); /* push continue offset */ - push_mjs_val(&mjs->loop_addresses, - mjs_mk_number(mjs, i + 1 /* OP_LOOP*/ + l1 + l2 + off)); + push_mjs_val( + &mjs->loop_addresses, + mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP*/ + l1 + l2 + off))); i += l1 + l2; break; } @@ -849,6 +854,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; } break; case OP_BREAK: { + size_t scopes_len; /* drop "continue" address */ mjs_pop_val(&mjs->loop_addresses); @@ -856,7 +862,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; /* restore scope index */ - size_t scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); + scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); assert(mjs_stack_size(&mjs->scopes) >= scopes_len); mjs->scopes.len = scopes_len * sizeof(mjs_val_t); @@ -1011,11 +1017,12 @@ mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, va_list ap; int i; mjs_err_t ret; - va_start(ap, nargs); mjs_val_t *args = calloc(1, sizeof(mjs_val_t) * nargs); + va_start(ap, nargs); for (i = 0; i < nargs; i++) { args[i] = va_arg(ap, mjs_val_t); } + va_end(ap); ret = mjs_apply(mjs, res, func, this_val, nargs, args); /* @@ -1029,19 +1036,19 @@ mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args) { - mjs_val_t r; + mjs_val_t r, prev_this_val, retval_stack_idx; int i; size_t addr = mjs_get_func_addr(func); LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); - mjs_val_t prev_this_val = mjs->vals.this_obj; + prev_this_val = mjs->vals.this_obj; /* Push undefined which will be later replaced with the return value */ mjs_push(mjs, MJS_UNDEFINED); /* Remember index by which return value should be written */ - mjs_val_t retval_stack_idx = mjs_mk_number(mjs, mjs_stack_size(&mjs->stack)); + retval_stack_idx = mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack)); // Push all arguments for (i = 0; i < nargs; i++) { diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index e090ff9..4fa1ef6 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -79,6 +79,7 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, sig_len = strlen(s); } + fflush(stdout); mjs_ffi_sig_init(sig); /* Parse return value type {{{ */ @@ -95,6 +96,7 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, } mjs_ffi_sig_set_val_type(sig, vtidx++, val_type); /* }}} */ + fflush(stdout); /* Parse function name (if any) {{{ */ /* @@ -150,9 +152,9 @@ MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s, /* Parse all args {{{ */ while (*tmp_e && *tmp_e != ')') { - tmp_e = cur; int level = 0; /* nested parens level */ int is_fp = 0; /* set to 1 is current arg is a callback function ptr */ + tmp_e = cur; /* Advance tmp_e until the next arg separator */ while (*tmp_e && (level > 0 || (*tmp_e != ',' && *tmp_e != ')'))) { @@ -267,11 +269,12 @@ struct ffi_cb_data { static union ffi_cb_data_val ffi_cb_impl_generic(void *param, struct ffi_cb_data *data) { struct mjs_ffi_cb_args *cbargs = (struct mjs_ffi_cb_args *) param; - mjs_val_t res = MJS_UNDEFINED; + mjs_val_t *args, res = MJS_UNDEFINED; union ffi_cb_data_val ret; int i; struct mjs *mjs = cbargs->mjs; mjs_ffi_ctype_t return_ctype = MJS_FFI_CTYPE_NONE; + mjs_err_t err; memset(&ret, 0, sizeof(ret)); mjs_own(mjs, &res); @@ -280,7 +283,7 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, assert(cbargs->sig.args_cnt > 0); /* Create JS arguments */ - mjs_val_t *args = calloc(1, sizeof(mjs_val_t) * cbargs->sig.args_cnt); + args = calloc(1, sizeof(mjs_val_t) * cbargs->sig.args_cnt); for (i = 0; i < cbargs->sig.args_cnt; i++) { mjs_ffi_ctype_t val_type = cbargs->sig.val_types[i + 1 /* first val_type is return value type */]; @@ -289,7 +292,7 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, args[i] = cbargs->userdata; break; case MJS_FFI_CTYPE_INT: - args[i] = mjs_mk_number(mjs, data->args[i].w); + args[i] = mjs_mk_number(mjs, (double) data->args[i].w); break; case MJS_FFI_CTYPE_BOOL: args[i] = mjs_mk_boolean(mjs, !!data->args[i].w); @@ -326,8 +329,8 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, /* Call JS function */ LOG(LL_VERBOSE_DEBUG, ("calling JS callback void-void %d from C", mjs_get_int(mjs, cbargs->func))); - mjs_err_t err = mjs_apply(mjs, &res, cbargs->func, MJS_UNDEFINED, - cbargs->sig.args_cnt, args); + err = mjs_apply(mjs, &res, cbargs->func, MJS_UNDEFINED, cbargs->sig.args_cnt, + args); /* * cbargs might be invalidated by the callback (if it called ffi_cb_free), so * null it out @@ -558,20 +561,18 @@ MJS_PRIVATE struct mjs_ffi_sig *mjs_get_ffi_sig_struct(mjs_val_t v) { } MJS_PRIVATE mjs_val_t mjs_mk_ffi_sig(struct mjs *mjs) { - (void) mjs; - struct mjs_ffi_sig *psig = new_ffi_sig(mjs); mjs_ffi_sig_init(psig); return mjs_ffi_sig_to_value(psig); } MJS_PRIVATE void mjs_ffi_sig_destructor(struct mjs *mjs, void *psig) { - (void) mjs; mjs_ffi_sig_free((mjs_ffi_sig_t *) psig); + (void) mjs; } MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs) { - mjs_err_t rcode = MJS_OK; + mjs_err_t e = MJS_OK; const char *sig_str = NULL; mjs_val_t sig_str_v = mjs_arg(mjs, 0); mjs_val_t ret_v = MJS_UNDEFINED; @@ -579,18 +580,13 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs) { size_t sig_str_len; sig_str = mjs_get_string(mjs, &sig_str_v, &sig_str_len); - - rcode = - mjs_parse_ffi_signature(mjs, sig_str, sig_str_len, psig, FFI_SIG_FUNC); - if (rcode != MJS_OK) { - goto clean; - } - + e = mjs_parse_ffi_signature(mjs, sig_str, sig_str_len, psig, FFI_SIG_FUNC); + if (e != MJS_OK) goto clean; ret_v = mjs_ffi_sig_to_value(psig); clean: mjs_return(mjs, ret_v); - return rcode; + return e; } MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { @@ -1071,7 +1067,13 @@ MJS_PRIVATE int mjs_ffi_is_regular_word_or_void(mjs_ffi_ctype_t type) { #ifdef _WIN32 void *dlsym(void *handle, const char *name) { - return GetProcAddress(GetModuleHandle(NULL), name); + static HANDLE msvcrt_dll; + void *sym = NULL; + if (msvcrt_dll == NULL) msvcrt_dll = GetModuleHandle("msvcrt.dll"); + if ((sym = GetProcAddress(GetModuleHandle(NULL), name)) == NULL) { + sym = GetProcAddress(msvcrt_dll, name); + } + return sym; } #elif !defined(__unix__) && !defined(__APPLE__) void *dlsym(void *handle, const char *name) { diff --git a/mjs/src/mjs_internal.h b/mjs/src/mjs_internal.h index 68bf7e0..390a891 100644 --- a/mjs/src/mjs_internal.h +++ b/mjs/src/mjs_internal.h @@ -72,7 +72,6 @@ typedef unsigned long uintptr_t; #define CS_DEFINE_DIRENT #include #else -#include #if defined(__unix__) || defined(__APPLE__) #include #endif diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index 3d33415..c50744d 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -67,39 +67,40 @@ static int findtok(int *toks, int tok) { static void emit_op(struct pstate *pstate, int tok) { assert(tok >= 0 && tok <= 255); emit_byte(pstate, OP_EXPR); - emit_byte(pstate, tok); + emit_byte(pstate, (uint8_t) tok); } // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. -#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ - do { \ - mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ - if (prev_op != TOK_EOF) emit_op(p, prev_op); \ - if (findtok(ops, p->tok.tok) != TOK_EOF) { \ - int op = p->tok.tok; \ - size_t off_if = 0; \ - /* For AND/OR, implement short-circuit evaluation */ \ - if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ - emit_byte(p, ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ - : OP_JMP_NEUTRAL_TRUE); \ - off_if = p->cur_idx; \ - emit_init_offset(p); \ - /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ - /* Just drop the first value, and evaluate the second one. */ \ - emit_byte(p, OP_DROP); \ - op = TOK_EOF; \ - } \ - pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ - \ - if (off_if != 0) { \ - mjs_bcode_insert_offset(p, p->mjs, off_if, \ - p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ - } \ - } \ - return res; \ +#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ + do { \ + mjs_err_t res = MJS_OK; \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + if (prev_op != TOK_EOF) emit_op(p, prev_op); \ + if (findtok(ops, p->tok.tok) != TOK_EOF) { \ + int op = p->tok.tok; \ + size_t off_if = 0; \ + /* For AND/OR, implement short-circuit evaluation */ \ + if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) { \ + emit_byte(p, \ + (uint8_t)(ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE \ + : OP_JMP_NEUTRAL_TRUE)); \ + off_if = p->cur_idx; \ + emit_init_offset(p); \ + /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */ \ + /* Just drop the first value, and evaluate the second one. */ \ + emit_byte(p, (uint8_t) OP_DROP); \ + op = TOK_EOF; \ + } \ + pnext1(p); \ + if ((res = f2(p, op)) != MJS_OK) return res; \ + \ + if (off_if != 0) { \ + mjs_bcode_insert_offset(p, p->mjs, off_if, \ + p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ + } \ + } \ + return res; \ } while (0) #define PARSE_RTL_BINOP(p, f1, f2, ops, prev_op) \ @@ -266,7 +267,7 @@ static enum mjs_err parse_literal(struct pstate *p, const struct tok *t) { int next_tok = ptest(p); emit_byte(p, OP_PUSH_STR); emit_str(p, t->ptr, t->len); - emit_byte(p, prev_tok == TOK_DOT ? OP_SWAP : OP_FIND_SCOPE); + emit_byte(p, (uint8_t)(prev_tok == TOK_DOT ? OP_SWAP : OP_FIND_SCOPE)); if (!findtok(s_assign_ops, next_tok) && !findtok(s_postfix_ops, next_tok) && /* TODO(dfrank): fix: it doesn't work for prefix ops */ @@ -289,8 +290,9 @@ static enum mjs_err parse_literal(struct pstate *p, const struct tok *t) { break; } case TOK_STR: { + size_t oldlen; emit_byte(p, OP_PUSH_STR); - size_t oldlen = bcode_gen->len; + oldlen = bcode_gen->len; embed_string(bcode_gen, p->cur_idx, t->ptr, t->len, EMBSTR_UNESCAPE); p->cur_idx += bcode_gen->len - oldlen; } break; @@ -602,6 +604,9 @@ static int check_for_in(struct pstate *p) { static mjs_err_t parse_for(struct pstate *p) { mjs_err_t res = MJS_OK; + size_t off_b, off_c, off_init_end; + size_t off_incr_begin, off_cond_begin, off_cond_end; + int buf_cur_idx; LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr)); EXPECT(p, TOK_KEYWORD_FOR); @@ -632,9 +637,9 @@ static mjs_err_t parse_for(struct pstate *p) { /* Before parsing condition statement, push break/continue offsets */ emit_byte(p, OP_LOOP); - size_t off_b = p->cur_idx; + off_b = p->cur_idx; emit_init_offset(p); - size_t off_c = p->cur_idx; + off_c = p->cur_idx; emit_init_offset(p); /* Parse init statement */ @@ -647,11 +652,11 @@ static mjs_err_t parse_for(struct pstate *p) { emit_byte(p, OP_DROP); emit_byte(p, OP_JMP); - size_t off_init_end = p->cur_idx; + off_init_end = p->cur_idx; emit_init_offset(p); - size_t off_incr_begin = p->cur_idx; - size_t off_cond_begin = p->cur_idx; + off_incr_begin = p->cur_idx; + off_cond_begin = p->cur_idx; /* Parse cond statement */ if ((res = parse_expr(p)) != MJS_OK) return res; @@ -659,7 +664,7 @@ static mjs_err_t parse_for(struct pstate *p) { /* Parse incr statement */ /* Incr statement should be placed before cond, so, adjust cur_idx */ - int buf_cur_idx = p->cur_idx; + buf_cur_idx = p->cur_idx; p->cur_idx = off_incr_begin; if ((res = parse_expr(p)) != MJS_OK) return res; @@ -679,7 +684,7 @@ static mjs_err_t parse_for(struct pstate *p) { /* p->cur_idx is now at the end of "cond" */ /* Exit the loop if false */ emit_byte(p, OP_JMP_FALSE); - size_t off_cond_end = p->cur_idx; + off_cond_end = p->cur_idx; emit_init_offset(p); /* Parse loop body */ @@ -902,6 +907,10 @@ MJS_PRIVATE mjs_err_t mjs_parse(const char *path, const char *buf, struct mjs *mjs) { mjs_err_t res = MJS_OK; struct pstate p; + size_t start_idx, llen; + int map_len; + mjs_header_item_t bcode_offset, map_offset, total_size; + pinit(path, buf, &p); p.mjs = mjs; p.cur_idx = p.mjs->bcode_gen.len; @@ -913,14 +922,14 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { */ /* Remember starting bcode position, and reserve the room for bcode header */ - size_t start_idx = p.mjs->bcode_gen.len; + start_idx = p.mjs->bcode_gen.len; mbuf_append(&p.mjs->bcode_gen, NULL, sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT); /* Append NULL-terminated filename */ mbuf_append(&p.mjs->bcode_gen, path, strlen(path) + 1 /* null-terminate */); - mjs_header_item_t bcode_offset = p.mjs->bcode_gen.len - start_idx; + bcode_offset = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET, &bcode_offset, sizeof(mjs_header_item_t)); @@ -932,14 +941,14 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { emit_byte(&p, OP_EXIT); /* remember map offset */ - mjs_header_item_t map_offset = p.mjs->bcode_gen.len - start_idx; + map_offset = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET, &map_offset, sizeof(mjs_header_item_t)); /* put map length varint */ - int map_len = p.offset_lineno_map.len; - size_t llen = cs_varint_llen(map_len); + map_len = p.offset_lineno_map.len; + llen = cs_varint_llen(map_len); mbuf_resize(&p.mjs->bcode_gen, p.mjs->bcode_gen.size + llen); cs_varint_encode(map_len, (uint8_t *) p.mjs->bcode_gen.buf + p.mjs->bcode_gen.len); @@ -949,7 +958,7 @@ mjs_parse(const char *path, const char *buf, struct mjs *mjs) { mbuf_append(&p.mjs->bcode_gen, p.offset_lineno_map.buf, p.offset_lineno_map.len); - mjs_header_item_t total_size = p.mjs->bcode_gen.len - start_idx; + total_size = p.mjs->bcode_gen.len - start_idx; memcpy(p.mjs->bcode_gen.buf + start_idx + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_TOTAL_SIZE, &total_size, sizeof(mjs_header_item_t)); diff --git a/mjs/src/mjs_string.c b/mjs/src/mjs_string.c index b31c4a9..9ff4987 100644 --- a/mjs/src/mjs_string.c +++ b/mjs/src/mjs_string.c @@ -41,6 +41,8 @@ int mjs_is_string(mjs_val_t v) { } mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { + struct mbuf *m; + mjs_val_t offset, tag = MJS_TAG_STRING_F; if (len == 0) { /* * Zero length for foreign string has a special meaning (that the foreign @@ -50,8 +52,8 @@ mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) { */ copy = 1; } - struct mbuf *m = copy ? &mjs->owned_strings : &mjs->foreign_strings; - mjs_val_t offset = m->len, tag = MJS_TAG_STRING_F; + m = copy ? &mjs->owned_strings : &mjs->foreign_strings; + offset = m->len; if (len == ~((size_t) 0)) len = strlen(p); @@ -167,7 +169,7 @@ const char *mjs_get_string(struct mjs *mjs, mjs_val_t *v, size_t *sizep) { char *s = mjs->foreign_strings.buf + offset; size = cs_varint_decode((uint8_t *) s, &llen); - memcpy(&p, s + llen, sizeof(p)); + memcpy((char **) &p, s + llen, sizeof(p)); } } else { assert(0); diff --git a/mjs/src/mjs_util.c b/mjs/src/mjs_util.c index 85c9309..d17a397 100644 --- a/mjs/src/mjs_util.c +++ b/mjs/src/mjs_util.c @@ -71,7 +71,7 @@ void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) { json_printf(out, "%s", ""); } else if (mjs_is_foreign(v)) { json_printf(out, "%s%lx%s", ""); + (unsigned long) (uintptr_t) mjs_get_ptr(mjs, v), ">"); } else if (mjs_is_function(v)) { json_printf(out, "%s%d%s", ""); } else if (mjs_is_null(v)) { @@ -238,6 +238,9 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i) { i += strlen((char *) (code + i + 1)) + 1; break; } + default: + LOG(LL_VERBOSE_DEBUG, ("%s", buf)); + break; } return i - start_i; } @@ -300,6 +303,7 @@ MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, const char *arg_name, enum mjs_type expected_type, mjs_val_t *parg) { mjs_val_t arg = MJS_UNDEFINED; + enum mjs_type actual_type; if (arg_num >= 0) { int nargs = mjs_nargs(mjs); @@ -314,7 +318,7 @@ MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num, arg = mjs->vals.this_obj; } - enum mjs_type actual_type = mjs_get_type(arg); + actual_type = mjs_get_type(arg); if (actual_type != expected_type) { mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "%s should be a %s, %s given", arg_name, mjs_stringify_type(expected_type), @@ -359,15 +363,15 @@ const char *mjs_get_bcode_filename_by_offset(struct mjs *mjs, int offset) { } int mjs_get_lineno_by_offset(struct mjs *mjs, int offset) { - int ret = 1; + int llen, map_len, prev_line_no, ret = 1; struct mjs_bcode_part *bp = mjs_bcode_part_get_by_offset(mjs, offset); + uint8_t *p, *pe; if (bp != NULL) { - mjs_header_item_t map_offset; + mjs_header_item_t map_offset, bcode_offset; memcpy(&map_offset, bp->data.p + 1 /* OP_BCODE_HEADER */ + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET, sizeof(map_offset)); - mjs_header_item_t bcode_offset; memcpy(&bcode_offset, bp->data.p + 1 /* OP_BCODE_HEADER */ + sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET, @@ -376,18 +380,17 @@ int mjs_get_lineno_by_offset(struct mjs *mjs, int offset) { offset -= (1 /* OP_BCODE_HEADER */ + bcode_offset) + bp->start_idx; /* get pointer to the length of the map followed by the map itself */ - uint8_t *p = (uint8_t *) bp->data.p + 1 /* OP_BCODE_HEADER */ + map_offset; + p = (uint8_t *) bp->data.p + 1 /* OP_BCODE_HEADER */ + map_offset; - int llen, map_len = cs_varint_decode(p, &llen); + map_len = cs_varint_decode(p, &llen); p += llen; - uint8_t *pe = p + map_len; + pe = p + map_len; - int prev_line_no = 1; + prev_line_no = 1; while (p < pe) { - int llen; - int cur_offset = cs_varint_decode(p, &llen); + int llen, line_no, cur_offset = cs_varint_decode(p, &llen); p += llen; - int line_no = cs_varint_decode(p, &llen); + line_no = cs_varint_decode(p, &llen); p += llen; if (cur_offset >= offset) { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index fa6abaa..5533873 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -14,8 +14,6 @@ extern "C" { #include "common/test_util.h" #include "mjs.c" -#include - #define ASSERT_EXEC_OK(_exec_) ASSERT_EXEC_RES(_exec_, MJS_OK) #define ASSERT_EXEC_RES(_exec_, _res_) \ @@ -97,14 +95,13 @@ typedef const char *(test_func_t)(struct mjs *mjs); */ static test_func_t *s_test_func; static const char *s_run_test_mjs(void) { + uint32_t objects_alive, props_alive, ffi_sigs_alive; struct mjs *mjs = mjs_create(); - const char *ret = s_test_func(mjs); mjs_gc(mjs, 1); - - uint32_t objects_alive = mjs->object_arena.alive; - uint32_t props_alive = mjs->property_arena.alive; - uint32_t ffi_sigs_alive = mjs->ffi_sig_arena.alive; + objects_alive = mjs->object_arena.alive; + props_alive = mjs->property_arena.alive; + ffi_sigs_alive = mjs->ffi_sig_arena.alive; /* * If test succeeds, run it again and check if memory usage is still the same @@ -570,7 +567,7 @@ static const char *test_func1() { int testfunc2(int a, double b) { // printf("called testfunc2 with a=%d, b=%lg\n", a, b); - return a + b; + return (int) (a + b); } static const char *test_func2() { @@ -589,7 +586,7 @@ static const char *test_func2() { int testfunc3(double a, double b) { // printf("called testfunc3 with a=%lg, b=%lg\n", a, b); - return a + b; + return (int) (a + b); } static const char *test_func3() { @@ -681,7 +678,7 @@ int ffi_test_i2i(int a0, int a1) { /* 3 arg, one double {{{ */ int ffi_test_iiid(int a0, int a1, double d2) { - return (d2 * a0 - a1) * 1000; + return (int) ((d2 * a0 - a1) * 1000); } bool ffi_test_biid(int a0, int a1, double d2) { @@ -697,7 +694,7 @@ double ffi_test_diid(int a0, int a1, double d2) { /* 3 arg, two doubles {{{ */ int ffi_test_iidd(int a0, double a1, double d2) { - return (d2 * a0 - a1) * 1000; + return (int) ((d2 * a0 - a1) * 1000); } bool ffi_test_bidd(int a0, double a1, double d2) { @@ -713,7 +710,7 @@ double ffi_test_didd(int a0, double a1, double d2) { /* 3 arg, one float {{{ */ int ffi_test_iiif(int a0, int a1, float f2) { - return (f2 * a0 - a1) * 1000; + return (int) ((f2 * a0 - a1) * 1000); } bool ffi_test_biif(int a0, int a1, float f2) { @@ -729,7 +726,7 @@ float ffi_test_fiif(int a0, int a1, float f2) { /* 3 arg, two floats {{{ */ int ffi_test_iiff(int a0, float a1, float f2) { - return (f2 * a0 - a1) * 1000; + return (int) ((f2 * a0 - a1) * 1000); } bool ffi_test_biff(int a0, float a1, float f2) { @@ -764,7 +761,7 @@ double ffi_test_d2d(double a, double b) { } int ffi_test_iid(int a, double b) { - return 1234 + a + b * 100; + return (int) (1234 + a + b * 100); } const char *ffi_test_s1s(const char *str) { @@ -854,61 +851,77 @@ static void ffi_test_inbuf(char *buf, int len) { } } +/* Old Visual Studio MSVC98 */ +#if _MSC_VER && _MSC_VER < 1700 +double round(double v) { + double intpart; + double fractpart = modf(v, &intpart); + return intpart + (fractpart < 0.5 ? 0 : 1); +} + +double fmax(double a, double b) { + return a > b ? a : b; +} + +double fmin(double a, double b) { + return a < b ? a : b; +} +#endif void *stub_dlsym(void *handle, const char *name) { - (void) handle; - if (strcmp(name, "ffi_get_null") == 0) return ffi_get_null; - if (strcmp(name, "ffi_set_byte") == 0) return ffi_set_byte; - if (strcmp(name, "ffi_test_i2i") == 0) return ffi_test_i2i; - if (strcmp(name, "ffi_test_iiid") == 0) return ffi_test_iiid; - if (strcmp(name, "ffi_test_biid") == 0) return ffi_test_biid; - if (strcmp(name, "ffi_test_diid") == 0) return ffi_test_diid; - if (strcmp(name, "ffi_test_iidd") == 0) return ffi_test_iidd; - if (strcmp(name, "ffi_test_bidd") == 0) return ffi_test_bidd; - if (strcmp(name, "ffi_test_didd") == 0) return ffi_test_didd; - if (strcmp(name, "ffi_test_iiif") == 0) return ffi_test_iiif; - if (strcmp(name, "ffi_test_biif") == 0) return ffi_test_biif; - if (strcmp(name, "ffi_test_fiif") == 0) return ffi_test_fiif; - if (strcmp(name, "ffi_test_iiff") == 0) return ffi_test_iiff; - if (strcmp(name, "ffi_test_biff") == 0) return ffi_test_biff; - if (strcmp(name, "ffi_test_fiff") == 0) return ffi_test_fiff; - if (strcmp(name, "ffi_test_iib") == 0) return ffi_test_iib; - if (strcmp(name, "ffi_test_bi") == 0) return ffi_test_bi; - if (strcmp(name, "ffi_test_i5i") == 0) return ffi_test_i5i; - if (strcmp(name, "ffi_test_i6i") == 0) return ffi_test_i6i; - if (strcmp(name, "ffi_test_d2d") == 0) return ffi_test_d2d; - if (strcmp(name, "ffi_test_iid") == 0) return ffi_test_iid; - if (strcmp(name, "ffi_test_s1s") == 0) return ffi_test_s1s; - if (strcmp(name, "ffi_dummy") == 0) return ffi_dummy; - if (strcmp(name, "ffi_test_cb_vu") == 0) return ffi_test_cb_vu; - if (strcmp(name, "ffi_test_cb_viu") == 0) return ffi_test_cb_viu; - if (strcmp(name, "ffi_test_cb_vui") == 0) return ffi_test_cb_vui; - if (strcmp(name, "ffi_test_cb_iiui") == 0) return ffi_test_cb_iiui; - if (strcmp(name, "ffi_test_cb_iiui2") == 0) return ffi_test_cb_iiui2; - if (strcmp(name, "ffi_test_cb_viiiiiu") == 0) return ffi_test_cb_viiiiiu; - if (strcmp(name, "ffi_test_inbuf") == 0) return ffi_test_inbuf; - if (strcmp(name, "malloc") == 0) return malloc; - if (strcmp(name, "calloc") == 0) return calloc; - if (strcmp(name, "free") == 0) return free; - if (strcmp(name, "mjs_mem_to_ptr") == 0) return mjs_mem_to_ptr; - if (strcmp(name, "mjs_mem_get_ptr") == 0) return mjs_mem_get_ptr; - if (strcmp(name, "mjs_mem_get_uint") == 0) return mjs_mem_get_uint; - if (strcmp(name, "mjs_mem_set_uint") == 0) return mjs_mem_set_uint; - if (strcmp(name, "mjs_mem_get_int") == 0) return mjs_mem_get_int; - if (strcmp(name, "ceil") == 0) return ceil; - if (strcmp(name, "floor") == 0) return floor; - if (strcmp(name, "rand") == 0) return rand; - if (strcmp(name, "round") == 0) return round; - if (strcmp(name, "fmax") == 0) return fmax; - if (strcmp(name, "fmin") == 0) return fmin; - if (strcmp(name, "fabs") == 0) return fabs; - if (strcmp(name, "sqrt") == 0) return sqrt; - if (strcmp(name, "exp") == 0) return exp; - if (strcmp(name, "log") == 0) return log; - if (strcmp(name, "pow") == 0) return pow; - if (strcmp(name, "sin") == 0) return sin; - if (strcmp(name, "cos") == 0) return cos; + if (strcmp(name, "ffi_get_null") == 0) return (void *) ffi_get_null; + if (strcmp(name, "ffi_set_byte") == 0) return (void *) ffi_set_byte; + if (strcmp(name, "ffi_test_i2i") == 0) return (void *) ffi_test_i2i; + if (strcmp(name, "ffi_test_iiid") == 0) return (void *) ffi_test_iiid; + if (strcmp(name, "ffi_test_biid") == 0) return (void *) ffi_test_biid; + if (strcmp(name, "ffi_test_diid") == 0) return (void *) ffi_test_diid; + if (strcmp(name, "ffi_test_iidd") == 0) return (void *) ffi_test_iidd; + if (strcmp(name, "ffi_test_bidd") == 0) return (void *) ffi_test_bidd; + if (strcmp(name, "ffi_test_didd") == 0) return (void *) ffi_test_didd; + if (strcmp(name, "ffi_test_iiif") == 0) return (void *) ffi_test_iiif; + if (strcmp(name, "ffi_test_biif") == 0) return (void *) ffi_test_biif; + if (strcmp(name, "ffi_test_fiif") == 0) return (void *) ffi_test_fiif; + if (strcmp(name, "ffi_test_iiff") == 0) return (void *) ffi_test_iiff; + if (strcmp(name, "ffi_test_biff") == 0) return (void *) ffi_test_biff; + if (strcmp(name, "ffi_test_fiff") == 0) return (void *) ffi_test_fiff; + if (strcmp(name, "ffi_test_iib") == 0) return (void *) ffi_test_iib; + if (strcmp(name, "ffi_test_bi") == 0) return (void *) ffi_test_bi; + if (strcmp(name, "ffi_test_i5i") == 0) return (void *) ffi_test_i5i; + if (strcmp(name, "ffi_test_i6i") == 0) return (void *) ffi_test_i6i; + if (strcmp(name, "ffi_test_d2d") == 0) return (void *) ffi_test_d2d; + if (strcmp(name, "ffi_test_iid") == 0) return (void *) ffi_test_iid; + if (strcmp(name, "ffi_test_s1s") == 0) return (void *) ffi_test_s1s; + if (strcmp(name, "ffi_dummy") == 0) return (void *) ffi_dummy; + if (strcmp(name, "ffi_test_cb_vu") == 0) return (void *) ffi_test_cb_vu; + if (strcmp(name, "ffi_test_cb_viu") == 0) return (void *) ffi_test_cb_viu; + if (strcmp(name, "ffi_test_cb_vui") == 0) return (void *) ffi_test_cb_vui; + if (strcmp(name, "ffi_test_cb_iiui") == 0) return (void *) ffi_test_cb_iiui; + if (strcmp(name, "ffi_test_cb_iiui2") == 0) return (void *) ffi_test_cb_iiui2; + if (strcmp(name, "ffi_test_cb_viiiiiu") == 0) return (void *) ffi_test_cb_viiiiiu; + if (strcmp(name, "ffi_test_inbuf") == 0) return (void *) ffi_test_inbuf; + if (strcmp(name, "malloc") == 0) return (void *) malloc; + if (strcmp(name, "calloc") == 0) return (void *) calloc; + if (strcmp(name, "free") == 0) return (void *) free; + if (strcmp(name, "mjs_mem_to_ptr") == 0) return (void *) mjs_mem_to_ptr; + if (strcmp(name, "mjs_mem_get_ptr") == 0) return (void *) mjs_mem_get_ptr; + if (strcmp(name, "mjs_mem_get_uint") == 0) return (void *) mjs_mem_get_uint; + if (strcmp(name, "mjs_mem_set_uint") == 0) return (void *) mjs_mem_set_uint; + if (strcmp(name, "mjs_mem_get_int") == 0) return (void *) mjs_mem_get_int; + if (strcmp(name, "ceil") == 0) return (void *) ceil; + if (strcmp(name, "floor") == 0) return (void *) floor; + if (strcmp(name, "rand") == 0) return (void *) rand; + if (strcmp(name, "round") == 0) return (void *) round; + if (strcmp(name, "fmax") == 0) return (void *) fmax; + if (strcmp(name, "fmin") == 0) return (void *) fmin; + if (strcmp(name, "fabs") == 0) return (void *) fabs; + if (strcmp(name, "sqrt") == 0) return (void *) sqrt; + if (strcmp(name, "exp") == 0) return (void *) exp; + if (strcmp(name, "log") == 0) return (void *) log; + if (strcmp(name, "pow") == 0) return (void *) pow; + if (strcmp(name, "sin") == 0) return (void *) sin; + if (strcmp(name, "cos") == 0) return (void *) cos; return NULL; + (void) handle; } const char *test_parse_ffi_signature(struct mjs *mjs) { @@ -943,7 +956,10 @@ const char *test_parse_ffi_signature(struct mjs *mjs) { mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "sdf ffi_dummy(int, int)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"sdf ffi_dummy(int, int)\": failed to parse val type \"sdf\""); + { + const char *rs = "bad ffi signature: \"sdf ffi_dummy(int, int)\": failed to parse val type \"sdf\""; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); mjs_set_errorf(mjs, MJS_OK, NULL); @@ -1002,42 +1018,60 @@ const char *test_parse_ffi_signature(struct mjs *mjs) { mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, void(*)(int, userdata), void(*)(), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, void(*)(int, userdata), void(*)(), userdata)\": only one callback is allowed"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(int, void(*)(int, userdata), void(*)(), userdata)\": only one callback is allowed"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); /* wrong signature: callback without userdata */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(void(*)(), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(void(*)(), userdata)\": bad ffi signature: \"void(*)()\": no userdata arg"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(void(*)(), userdata)\": bad ffi signature: \"void(*)()\": no userdata arg"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); /* wrong signature: callback is present, userdata is not */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, void(*)(userdata))", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, void(*)(userdata))\": callback and userdata should be either both present or both absent"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(int, void(*)(userdata))\": callback and userdata should be either both present or both absent"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); /* wrong signature: callback is not present, userdata is */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, userdata)\": callback and userdata should be either both present or both absent"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(int, userdata)\": callback and userdata should be either both present or both absent"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); /* wrong signature: callback taking another callback */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(void(*)(void(*)(userdata), userdata), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(void(*)(void(*)(userdata), userdata), userdata)\": bad ffi signature: \"void(*)(void(*)(userdata), userdata)\": callback can't take another callback"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(void(*)(void(*)(userdata), userdata), userdata)\": bad ffi signature: \"void(*)(void(*)(userdata), userdata)\": callback can't take another callback"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); /* wrong signature: callback with double arg */ mjs_set_errorf(mjs, MJS_OK, NULL); ASSERT_EQ( mjs_parse_ffi_signature(mjs, "int ffi_dummy(int, void(*)(double, double, userdata), userdata)", ~0, &sig, FFI_SIG_FUNC), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"int ffi_dummy(int, void(*)(double, double, userdata), userdata)\": bad ffi signature: \"void(*)(double, double, userdata)\": the callback signature is valid, but there's no existing callback implementation for it"); + { + const char *rs = "bad ffi signature: \"int ffi_dummy(int, void(*)(double, double, userdata), userdata)\": bad ffi signature: \"void(*)(double, double, userdata)\": the callback signature is valid, but there's no existing callback implementation for it"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_ffi_sig_free(&sig); return NULL; @@ -1539,7 +1573,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(int, int, foo(*)(userdata), userdata)" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(int, int, foo(*)(userdata), userdata)\": bad ffi signature: \"foo(*)(userdata)\": failed to parse val type \"foo\""); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(int, int, foo(*)(userdata), userdata)\": bad ffi signature: \"foo(*)(userdata)\": failed to parse val type \"foo\""; + ASSERT_STREQ(mjs->error_msg, rs); + } /* --- */ @@ -1549,7 +1586,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(int, int, void(*)(userdata, foo), userdata)" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata, foo), userdata)\": bad ffi signature: \"void(*)(userdata, foo)\": failed to parse val type \"foo\""); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata, foo), userdata)\": bad ffi signature: \"void(*)(userdata, foo)\": failed to parse val type \"foo\""; + ASSERT_STREQ(mjs->error_msg, rs); + } /* --- */ @@ -1559,7 +1599,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(int, int, void(*)(), userdata)" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(int, int, void(*)(), userdata)\": bad ffi signature: \"void(*)()\": no userdata arg"); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(int, int, void(*)(), userdata)\": bad ffi signature: \"void(*)()\": no userdata arg"; + ASSERT_STREQ(mjs->error_msg, rs); + } /* --- */ @@ -1569,7 +1612,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(int, int, void(*)(userdata))" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata))\": callback and userdata should be either both present or both absent"); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata))\": callback and userdata should be either both present or both absent"; + ASSERT_STREQ(mjs->error_msg, rs); + } /* --- */ @@ -1579,7 +1625,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(userdata, int, void(*)(userdata), userdata)" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(userdata, int, void(*)(userdata), userdata)\": more than one userdata arg: #0 and #3"); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(userdata, int, void(*)(userdata), userdata)\": more than one userdata arg: #0 and #3"; + ASSERT_STREQ(mjs->error_msg, rs); + } /* --- */ @@ -1589,7 +1638,10 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { "void ffi_dummy(int, int, void(*)(userdata, userdata), userdata)" ); ), &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata, userdata), userdata)\": bad ffi signature: \"void(*)(userdata, userdata)\": more than one userdata arg: #0 and #1"); + { + const char *rs = "bad ffi signature: \"void ffi_dummy(int, int, void(*)(userdata, userdata), userdata)\": bad ffi signature: \"void(*)(userdata, userdata)\": more than one userdata arg: #0 and #1"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_disown(mjs, &res); @@ -1647,10 +1699,16 @@ const char *test_errors(struct mjs *mjs) { ASSERT_STREQ(mjs->error_msg, "implicit type conversion is prohibited"); ASSERT_EQ(mjs_exec(mjs, "load('foo/bar/bazzz')", &res), MJS_FILE_READ_ERROR); - ASSERT_STREQ(mjs->error_msg, "failed to exec file \"foo/bar/bazzz\": failed to read file \"foo/bar/bazzz\""); + { + const char *rs = "failed to exec file \"foo/bar/bazzz\": failed to read file \"foo/bar/bazzz\""; + ASSERT_STREQ(mjs->error_msg, rs); + } ASSERT_EQ(mjs_exec(mjs, "load('tests/module2.js')", &res), MJS_TYPE_ERROR); - ASSERT_STREQ(mjs->error_msg, "failed to exec file \"tests/module2.js\": bad ffi signature: \"int foo(int)\": dlsym('foo') failed"); + { + const char *rs = "failed to exec file \"tests/module2.js\": bad ffi signature: \"int foo(int)\": dlsym('foo') failed"; + ASSERT_STREQ(mjs->error_msg, rs); + } mjs_disown(mjs, &res); return NULL; @@ -1659,7 +1717,7 @@ const char *test_errors(struct mjs *mjs) { const char *test_varint(void) { #define TEST_VARINT_CASE(number, encoded_length) \ do { \ - uint8_t buf[100]; \ + unsigned char buf[100]; \ int llen; \ ASSERT_EQ(cs_varint_encode((number), buf), (encoded_length)); \ ASSERT_EQ(cs_varint_decode(buf, &llen), (number)); \ @@ -2640,6 +2698,7 @@ const char *test_arrays(struct mjs *mjs) { } const char *test_json(struct mjs *mjs) { + const char *json_val = "{\"null\":null,\"arr\":[1,2,{\"foo\":100}],\"bar\":\"hey\",\"foo\":1}"; mjs_val_t res = MJS_UNDEFINED; mjs_own(mjs, &res); @@ -2647,25 +2706,28 @@ const char *test_json(struct mjs *mjs) { "let o = {foo: 1, bar: 'hey', arr: [1, 2, {foo: 100,}], 'null': null, 'undefined': undefined}; " "JSON.stringify(o)", &res)); - ASSERT_STREQ(mjs_get_cstring(mjs, &res), "{\"null\":null,\"arr\":[1,2,{\"foo\":100}],\"bar\":\"hey\",\"foo\":1}"); + { + const char *rs = "{\"null\":null,\"arr\":[1,2,{\"foo\":100}],\"bar\":\"hey\",\"foo\":1}"; + ASSERT_STREQ(mjs_get_cstring(mjs, &res), rs); + } - ASSERT_EXEC_OK(mjs_exec(mjs, - "JSON.stringify(\"foo\")", - &res)); - ASSERT_STREQ(mjs_get_cstring(mjs, &res), "\"foo\""); + { + const char *aa = "JSON.stringify(\"foo\")", *bb = "\"foo\""; + ASSERT_EXEC_OK(mjs_exec(mjs, aa, &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), bb); + } /* Test circular links and sparse arrays */ ASSERT_EXEC_OK(mjs_exec(mjs, "o.arr[10] = o;" "JSON.stringify(o)", &res)); - ASSERT_STREQ( - mjs_get_cstring(mjs, &res), - "{\"null\":null,\"arr\":[1,2,{\"foo\":100},null,null,null,null,null,null,null,[Circular]],\"bar\":\"hey\",\"foo\":1}" - ); + { + const char *rs = "{\"null\":null,\"arr\":[1,2,{\"foo\":100},null,null,null,null,null,null,null,[Circular]],\"bar\":\"hey\",\"foo\":1}"; + ASSERT_STREQ(mjs_get_cstring(mjs, &res), rs); + } /* Test parse */ - const char *json_val = "{\"null\":null,\"arr\":[1,2,{\"foo\":100}],\"bar\":\"hey\",\"foo\":1}"; ASSERT_EXEC_OK(mjs_exec(mjs, "let o = {foo: 1, bar: 'hey', arr: [1, 2, {foo: 100}], 'null': null, 'undefined': undefined}; " "let s = JSON.stringify(o);" @@ -2829,13 +2891,14 @@ const char *test_string(struct mjs *mjs) { const char *test_call_api(struct mjs *mjs) { mjs_val_t func = MJS_UNDEFINED; + mjs_val_t res = MJS_UNDEFINED; + mjs_val_t obj = MJS_UNDEFINED; + mjs_own(mjs, &func); /* function with no arguments */ ASSERT_EQ(mjs_exec(mjs, "let a=123; function(){ a += 1; return a; }", &func), MJS_OK); - mjs_val_t res = MJS_UNDEFINED; - mjs_val_t obj = MJS_UNDEFINED; mjs_own(mjs, &res); mjs_own(mjs, &obj); @@ -2920,13 +2983,11 @@ const char *test_long_jump(struct mjs *mjs) { } const char *test_foreign_str(struct mjs *mjs) { + unsigned char *ptr = NULL; mjs_val_t res = MJS_UNDEFINED; - mjs_own(mjs, &res); - - uint8_t *ptr = NULL; + mjs_own(mjs, &res); mjs_set_ffi_resolver(mjs, stub_dlsym); - ASSERT_EXEC_OK(mjs_exec(mjs, STRINGIFY( let calloc = ffi('void *calloc(int, int)'); @@ -2934,7 +2995,7 @@ const char *test_foreign_str(struct mjs *mjs) { let str = fstr(ptr, 3); ptr ), &res)); - ptr = (uint8_t *)mjs_get_ptr(mjs, res); + ptr = (unsigned char *)mjs_get_ptr(mjs, res); ASSERT_EXEC_OK(mjs_exec(mjs, "str.length", &res)); ASSERT_EQ(mjs_get_int(mjs, res), 3); @@ -2965,13 +3026,11 @@ const char *test_foreign_str(struct mjs *mjs) { } const char *test_foreign_ptr(struct mjs *mjs) { + unsigned char *ptr = NULL; mjs_val_t res = MJS_UNDEFINED; - mjs_own(mjs, &res); + mjs_own(mjs, &res); mjs_set_ffi_resolver(mjs, stub_dlsym); - - uint8_t *ptr = NULL; - ASSERT_EXEC_OK(mjs_exec(mjs, STRINGIFY( let get_null = ffi('void *ffi_get_null()'); @@ -3016,7 +3075,7 @@ const char *test_foreign_ptr(struct mjs *mjs) { let ptr = calloc(100, 1); ptr; ), &res)); - ptr = (uint8_t *)mjs_get_ptr(mjs, res); + ptr = (unsigned char *)mjs_get_ptr(mjs, res); ASSERT_EQ(ptr[0], 0); ASSERT_EXEC_OK(mjs_exec(mjs, "ptr[0] = 10; ptr[10] = 20;", &res)); @@ -3194,6 +3253,7 @@ const char *test_backtrace(struct mjs *mjs) { * when RUN_TEST_MJS does the second pass, it's already loaded. */ const char *test_load(void) { + size_t len1, len2; struct mjs *mjs = mjs_create(); mjs_val_t func_load = MJS_UNDEFINED; @@ -3229,7 +3289,7 @@ const char *test_load(void) { ASSERT_EXEC_OK(mjs_apply(mjs, &res, func_add_foo_to_s, MJS_UNDEFINED, 0, NULL)); ASSERT_EXEC_OK(mjs_apply(mjs, &res, func_load, MJS_UNDEFINED, 0, NULL)); - size_t len1 = mjs->bcode_parts.len; + len1 = mjs->bcode_parts.len; ASSERT_EXEC_OK(mjs_call(mjs, &res, func_set_foo, MJS_UNDEFINED, 1, res)); @@ -3240,7 +3300,7 @@ const char *test_load(void) { ASSERT_EXEC_OK(mjs_apply(mjs, &res, func_add_foo_to_s, MJS_UNDEFINED, 0, NULL)); ASSERT_EXEC_OK(mjs_apply(mjs, &res, func_load, MJS_UNDEFINED, 0, NULL)); - size_t len2 = mjs->bcode_parts.len; + len2 = mjs->bcode_parts.len; ASSERT_EQ(len1, len2); ASSERT_EXEC_OK(mjs_call(mjs, &res, func_set_foo, MJS_UNDEFINED, 1, res)); @@ -3266,9 +3326,10 @@ const char *test_load(void) { const char *test_dataview(struct mjs *mjs) { mjs_val_t res = MJS_UNDEFINED; - uint8_t buf[20] = "abcd1234 :-)\xff\xff\xff\xff"; - mjs_own(mjs, &res); + unsigned char *ptr = NULL; + unsigned char buf[20] = "abcd1234 :-)\xff\xff\xff\xff"; + mjs_own(mjs, &res); mjs_set_ffi_resolver(mjs, stub_dlsym); ASSERT_EQ(mjs_mem_get_uint(buf + 12, 4, 1), 0xffffffff); @@ -3297,15 +3358,13 @@ const char *test_dataview(struct mjs *mjs) { CHECK_NUMERIC("peeku(peek(buf,12), 4, 1)", 0xffffffff); - uint8_t *ptr = NULL; - ASSERT_EXEC_OK(mjs_exec(mjs, STRINGIFY( let calloc = ffi('void *calloc(int, int)'); let ptr = calloc(100, 1); ptr; ), &res)); - ptr = (uint8_t *)mjs_get_ptr(mjs, res); + ptr = (unsigned char *)mjs_get_ptr(mjs, res); ptr[5] = 0x30; ptr[6] = 0x31; @@ -3515,13 +3574,13 @@ const char *test_lib_math(struct mjs *mjs) { ASSERT_EQ(mjs_get_double(mjs, res), exp(5)); ASSERT_EXEC_OK(mjs_exec(mjs, "Math.log(5.5)", &res)); - ASSERT_EQ(mjs_get_double(mjs, res), log(5.5)); + ASSERT(fabs(mjs_get_double(mjs, res) - log(5.5)) < 0.0001); ASSERT_EXEC_OK(mjs_exec(mjs, "Math.pow(3, 5)", &res)); ASSERT_EQ(mjs_get_double(mjs, res), pow(3, 5)); ASSERT_EXEC_OK(mjs_exec(mjs, "Math.sin(0.2)", &res)); - ASSERT_EQ(mjs_get_double(mjs, res), sin(0.2)); + ASSERT(fabs(mjs_get_double(mjs, res) - sin(0.2)) < 0.0001); ASSERT_EXEC_OK(mjs_exec(mjs, "Math.cos(0.2)", &res)); ASSERT_EQ(mjs_get_double(mjs, res), cos(0.2)); From bea470c01d0b979cc7698d93b413bc1da67da56a Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 16 Nov 2017 00:04:01 +0200 Subject: [PATCH 104/265] Add docs for JS Math API PUBLISHED_FROM=5107dbb50f23c4b59ac38a510a32e0f5b282e184 --- mjs/lib/api_math.js | 48 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/mjs/lib/api_math.js b/mjs/lib/api_math.js index 66d815d..2ca7f0f 100644 --- a/mjs/lib/api_math.js +++ b/mjs/lib/api_math.js @@ -1,16 +1,62 @@ let Math = { + + // ## **`Math.ceil(x)`** + // Rounds x upward, returning the smallest integral value that is not less + // than x. ceil: ffi('double ceil(double)'), + + // ## **`Math.floor(x)`** + // Rounds x downward, returning the largest integral value that is not + // greater than x. floor: ffi('double floor(double)'), + + // ## **`Math.round(x)`** + // Returns the integral value that is nearest to x, with halfway cases + // rounded away from zero. round: ffi('double round(double)'), + + // ## **`Math.max(x, y)`** + // Returns the larger of its arguments: either `x` or `y`. + // If one of the arguments in a NaN, the other is returned. max: ffi('double fmax(double, double)'), + + // ## **`Math.min(x, y)`** + // Returns the smaller of its arguments: either `x` or `y`. + // If one of the arguments in a NaN, the other is returned. min: ffi('double fmin(double, double)'), + + // ## **`Math.abs(x)`** + // Returns the absolute value of `x`: |x|. abs: ffi('double fabs(double)'), + + // ## **`Math.sqrt(x)`** + // Returns the square root of `x`. sqrt: ffi('double sqrt(double)'), + + // ## **`Math.floor(x)`** + // Returns the base-e exponential function of `x`, which is e raised to the + // power `x`. exp: ffi('double exp(double)'), + + // ## **`Math.log(x)`** + // Returns the natural logarithm of `x`. log: ffi('double log(double)'), + + // ## **`Math.pow(base, exponent)`** + // Returns `base` raised to the power `exponent` pow: ffi('double pow(double, double)'), + + // ## **`Math.sin(x)`** + // Returns the sine of an angle of `x` radians. sin: ffi('double sin(double)'), + + // ## **`Math.cos(x)`** + // Returns the cosine of an angle of `x` radians. cos: ffi('double cos(double)'), - rand: ffi('int rand()'), + + // ## **`Math.random(x)`** + // Returns the pseudo-random number from 0.0 to 1.0 random: function() { return Math.rand() / 0x7fffffff; }, + + rand: ffi('int rand()'), }; From 2827bd00b59bdc176a010b22fc4acde9b580d6c2 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 15 Nov 2017 23:25:02 +0200 Subject: [PATCH 105/265] Add docs for JS DataView API PUBLISHED_FROM=29ebe9d49f4f7935316c54c883ab493963a8c463 --- mjs/lib/api_dataview.js | 118 ++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 22 deletions(-) diff --git a/mjs/lib/api_dataview.js b/mjs/lib/api_dataview.js index e52a661..428216a 100644 --- a/mjs/lib/api_dataview.js +++ b/mjs/lib/api_dataview.js @@ -1,4 +1,4 @@ -// DataView API. +// **DataView API** // // See the original API definition at [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView). // @@ -8,20 +8,39 @@ // - Since there are no constructors in mJS, `DataView.create()` should be // used instead; // - No float support yet (will be added) -// -// Example: -// -// ```javascript -// load("lib/api_dataview.js"); -// let calloc = ffi('void *calloc(int, int)'); -// let ptr = calloc(100, 1); -// let dw = DataView.create(ptr, 0, 100); -// -// dw.setUint8(0xff); -// ``` let DataView = { + // ## **`DataView.create(buf, offset, len)`** + // Create a DataView object instance. `buf` is a pointer to a plain byte + // array, `offset` is an offset in in this buffer to start dataview from, and + // `len` is a length managed by dataview. + // + // Return value: an object with the methods described below. + // + // Example: + // ```javascript + // load("api_dataview.js"); + // let calloc = ffi('void *calloc(int, int)'); + // let ptr = calloc(100, 1); + // let dw = DataView.create(ptr, 0, 100); + // + // dw.setUint8(2, 0xff); + // ``` + create: function(buf, off, len) { + let ret = Object.create(this._prot); + if (off !== undefined) { + buf += off; + } + ret._buf = buf; + ret._len = len; + return ret; + }, + _prot: { + + // ## **`myDW.getInt8(idx)`** + // Get a signed byte value from the dataview's buffer at the given index + // `idx`. Returned value: a number from -128 to 127. getInt8: function(idx) { if (!DataView._cl(idx, this._len, 1)) { return undefined; @@ -30,6 +49,10 @@ let DataView = { DataView._pk(this._buf, idx), 1, false ); }, + + // ## **`myDW.getUint8(idx)`** + // Get an unsigned byte value from the dataview's buffer at the given index + // `idx`. Returned value: a number from 0 to 255. getUint8: function(idx) { if (!DataView._cl(idx, this._len, 1)) { return undefined; @@ -38,6 +61,12 @@ let DataView = { DataView._pk(this._buf, idx), 1, false ); }, + + // ## **`myDW.getInt16(idx, le)`** + // Get a signed 2-byte value from the dataview's buffer at the given index + // `idx`. By default the data interpreted as big-endian; if `le` is true, + // then little-endian will be used. + // Returned value: a number from -32768 to 32767. getInt16: function(idx, le) { if (!DataView._cl(idx, this._len, 2)) { return undefined; @@ -46,6 +75,12 @@ let DataView = { DataView._pk(this._buf, idx), 2, !le ); }, + + // ## **`myDW.getUint16(idx, le)`** + // Get an unsigned 2-byte value from the dataview's buffer at the given + // index `idx`. By default the data interpreted as big-endian; if `le` is + // true, then little-endian will be used. + // Returned value: a number from 0 to 65535. getUint16: function(idx, le) { if (!DataView._cl(idx, this._len, 2)) { return undefined; @@ -54,6 +89,12 @@ let DataView = { DataView._pk(this._buf, idx), 2, !le ); }, + + // ## **`myDW.getInt32(idx, le)`** + // Get a signed 4-byte value from the dataview's buffer at the given index + // `idx`. By default the data interpreted as big-endian; if `le` is true, + // then little-endian will be used. + // Returned value: a number from -2147483648 to 2147483647. getInt32: function(idx, le) { if (!DataView._cl(idx, this._len, 4)) { return undefined; @@ -62,6 +103,12 @@ let DataView = { DataView._pk(this._buf, idx), 4, !le ); }, + + // ## **`myDW.getUint32(idx, le)`** + // Get an unsigned 4-byte value from the dataview's buffer at the given + // index `idx`. By default the data interpreted as big-endian; if `le` is + // true, then little-endian will be used. + // Returned value: a number from 0 to 4294967295. getUint32: function(idx, le) { if (!DataView._cl(idx, this._len, 4)) { return undefined; @@ -71,6 +118,10 @@ let DataView = { ); }, + // ## **`myDW.setInt8(idx, val)`** + // Set a signed byte value into the dataview's buffer at the given index + // `idx`. `val` should be a number from -128 to 127. + // Returned value: none. setInt8: function(idx, val) { if (!DataView._cl(idx, this._len, 1)) { return undefined; @@ -79,6 +130,11 @@ let DataView = { DataView._pk(this._buf, idx), val, 1, false ); }, + + // ## **`myDW.setUint8(idx, val)`** + // Set an unsigned byte value into the dataview's buffer at the given index + // `idx`. `val` should be a number from -128 to 127. + // Returned value: none. setUint8: function(idx, val) { if (!DataView._cl(idx, this._len, 1)) { return undefined; @@ -87,6 +143,13 @@ let DataView = { DataView._pk(this._buf, idx), val, 1, false ); }, + + // ## **`myDW.setInt16(idx, val, le)`** + // Set a signed 2-byte value into the dataview's buffer at the given index + // `idx`. `val` should be a number from -32768 to 32767. By default the + // data is written in big-endian format; if `le` is true, then + // little-endian will be used. + // Returned value: none. setInt16: function(idx, val, le) { if (!DataView._cl(idx, this._len, 2)) { return undefined; @@ -95,6 +158,13 @@ let DataView = { DataView._pk(this._buf, idx), val, 2, !le ); }, + + // ## **`myDW.setUint16(idx, val, le)`** + // Set an unsigned 2-byte value into the dataview's buffer at the given + // index `idx`. `val` should be a number from 0 to 65535. By default the + // data is written in big-endian format; if `le` is true, then + // little-endian will be used. + // Returned value: none. setUint16: function(idx, val, le) { if (!DataView._cl(idx, this._len, 2)) { return undefined; @@ -103,6 +173,13 @@ let DataView = { DataView._pk(this._buf, idx), val, 2, !le ); }, + + // ## **`myDW.setInt32(idx, val, le)`** + // Set a signed 4-byte value into the dataview's buffer at the given index + // `idx`. `val` should be a number from -2147483648 to 2147483647. By + // default the data is written in big-endian format; if `le` is true, then + // little-endian will be used. + // Returned value: none. setInt32: function(idx, val, le) { if (!DataView._cl(idx, this._len, 4)) { return undefined; @@ -111,6 +188,13 @@ let DataView = { DataView._pk(this._buf, idx), val, 4, !le ); }, + + // ## **`myDW.setUint32(idx, val, le)`** + // Set an unsigned 4-byte value into the dataview's buffer at the given + // index `idx`. `val` should be a number from 0 to 4294967295. By default + // the data is written in big-endian format; if `le` is true, then + // little-endian will be used. + // Returned value: none. setUint32: function(idx, val, le) { if (!DataView._cl(idx, this._len, 4)) { return undefined; @@ -121,16 +205,6 @@ let DataView = { }, }, - create: function(buf, off, len) { - let ret = Object.create(this._prot); - if (off !== undefined) { - buf += off; - } - ret._buf = buf; - ret._len = len; - return ret; - }, - _cl: function(idx, len, ilen) { if (len !== undefined && idx + ilen > len) { die(DataView._errm); From c203bac28dfbcebcaf9aafaca29a809d1da77274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sat, 18 Nov 2017 11:32:02 +0000 Subject: [PATCH 106/265] FFI mg_str * PUBLISHED_FROM=e19555c1e6117318bdacc87b0ab5831017afe085 --- mjs.c | 34 ++++++++++++++++++++++++++++++++-- mjs/src/mjs_ffi.c | 31 ++++++++++++++++++++++++++++++- mjs/src/mjs_ffi.h | 3 ++- mjs/tests/unit_test.c | 10 ++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index 56f0eac..6ecd2c0 100644 --- a/mjs.c +++ b/mjs.c @@ -2613,8 +2613,8 @@ void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); #define MJS_FFI_H_ /* Amalgamated: #include "mjs/src/ffi/ffi.h" */ -/* Amalgamated: #include "mjs/src/mjs_internal.h" */ /* Amalgamated: #include "mjs/src/mjs_ffi_public.h" */ +/* Amalgamated: #include "mjs/src/mjs_internal.h" */ #if defined(__cplusplus) extern "C" { @@ -2635,6 +2635,7 @@ enum mjs_ffi_ctype { MJS_FFI_CTYPE_FLOAT, MJS_FFI_CTYPE_CHAR_PTR, MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, MJS_FFI_CTYPE_INVALID, }; typedef uint8_t mjs_ffi_ctype_t; @@ -9590,13 +9591,15 @@ mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, * All rights reserved */ +/* Amalgamated: #include "common/mg_str.h" */ + +/* Amalgamated: #include "mjs/src/ffi/ffi.h" */ /* Amalgamated: #include "mjs/src/mjs_core.h" */ /* Amalgamated: #include "mjs/src/mjs_exec.h" */ /* Amalgamated: #include "mjs/src/mjs_internal.h" */ /* Amalgamated: #include "mjs/src/mjs_primitive.h" */ /* Amalgamated: #include "mjs/src/mjs_string.h" */ /* Amalgamated: #include "mjs/src/mjs_util.h" */ -/* Amalgamated: #include "mjs/src/ffi/ffi.h" */ /* * on linux this is enabled only if __USE_GNU is defined, but we cannot set it @@ -9643,6 +9646,9 @@ static mjs_ffi_ctype_t parse_cval_type(struct mjs *mjs, const char *s, return MJS_FFI_CTYPE_DOUBLE; } else if (strncmp(s, "float", e - s) == 0) { return MJS_FFI_CTYPE_FLOAT; + } else if (strncmp(s, "struct mg_str *", e - s) == 0 || + strncmp(s, "struct mg_str*", e - s) == 0) { + return MJS_FFI_CTYPE_STRUCT_MG_STR_PTR; } else if (strncmp(s, "char*", 5) == 0 || strncmp(s, "char *", 6) == 0) { return MJS_FFI_CTYPE_CHAR_PTR; } else if (strncmp(s, "void*", 5) == 0 || strncmp(s, "void *", 6) == 0) { @@ -9899,6 +9905,11 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_FLOAT: args[i] = mjs_mk_number(mjs, data->args[i].f); break; + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + struct mg_str *s = (struct mg_str *) (void *) data->args[i].w; + args[i] = mjs_mk_string(mjs, s->p, s->len, 1); + break; + } default: /* should never be here */ LOG(LL_ERROR, ("unexpected val type for arg #%d: %d\n", i, val_type)); @@ -10195,6 +10206,7 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { * mjs_val_t itself */ mjs_val_t argvs[FFI_MAX_ARGS_CNT]; + struct mg_str argvmgstr[FFI_MAX_ARGS_CNT]; if (mjs_is_ffi_sig(sig_v)) { psig = mjs_get_ffi_sig_struct(sig_v); @@ -10294,6 +10306,23 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } ffi_set_word(&args[i], intval); } break; + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + if (!mjs_is_string(arg)) { + ret = MJS_TYPE_ERROR; + mjs_prepend_errorf( + mjs, ret, "actual arg #%d is not a string (the type idx is: %s)", + i, mjs_typeof(arg)); + goto clean; + } + argvs[i] = arg; + argvmgstr[i].p = mjs_get_string(mjs, &argvs[i], &argvmgstr[i].len); + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ + ffi_set_ptr(&args[i], (void *) &argvmgstr[i]); + break; + } case MJS_FFI_CTYPE_BOOL: { int intval = 0; if (mjs_is_number(arg)) { @@ -10593,6 +10622,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, case MJS_FFI_CTYPE_BOOL: case MJS_FFI_CTYPE_VOID_PTR: case MJS_FFI_CTYPE_CHAR_PTR: + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: case MJS_FFI_CTYPE_DOUBLE: case MJS_FFI_CTYPE_FLOAT: /* Do nothing */ diff --git a/mjs/src/mjs_ffi.c b/mjs/src/mjs_ffi.c index 4fa1ef6..016d6fb 100644 --- a/mjs/src/mjs_ffi.c +++ b/mjs/src/mjs_ffi.c @@ -3,13 +3,15 @@ * All rights reserved */ +#include "common/mg_str.h" + +#include "mjs/src/ffi/ffi.h" #include "mjs/src/mjs_core.h" #include "mjs/src/mjs_exec.h" #include "mjs/src/mjs_internal.h" #include "mjs/src/mjs_primitive.h" #include "mjs/src/mjs_string.h" #include "mjs/src/mjs_util.h" -#include "mjs/src/ffi/ffi.h" /* * on linux this is enabled only if __USE_GNU is defined, but we cannot set it @@ -56,6 +58,9 @@ static mjs_ffi_ctype_t parse_cval_type(struct mjs *mjs, const char *s, return MJS_FFI_CTYPE_DOUBLE; } else if (strncmp(s, "float", e - s) == 0) { return MJS_FFI_CTYPE_FLOAT; + } else if (strncmp(s, "struct mg_str *", e - s) == 0 || + strncmp(s, "struct mg_str*", e - s) == 0) { + return MJS_FFI_CTYPE_STRUCT_MG_STR_PTR; } else if (strncmp(s, "char*", 5) == 0 || strncmp(s, "char *", 6) == 0) { return MJS_FFI_CTYPE_CHAR_PTR; } else if (strncmp(s, "void*", 5) == 0 || strncmp(s, "void *", 6) == 0) { @@ -312,6 +317,11 @@ static union ffi_cb_data_val ffi_cb_impl_generic(void *param, case MJS_FFI_CTYPE_FLOAT: args[i] = mjs_mk_number(mjs, data->args[i].f); break; + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + struct mg_str *s = (struct mg_str *) (void *) data->args[i].w; + args[i] = mjs_mk_string(mjs, s->p, s->len, 1); + break; + } default: /* should never be here */ LOG(LL_ERROR, ("unexpected val type for arg #%d: %d\n", i, val_type)); @@ -608,6 +618,7 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { * mjs_val_t itself */ mjs_val_t argvs[FFI_MAX_ARGS_CNT]; + struct mg_str argvmgstr[FFI_MAX_ARGS_CNT]; if (mjs_is_ffi_sig(sig_v)) { psig = mjs_get_ffi_sig_struct(sig_v); @@ -707,6 +718,23 @@ MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) { } ffi_set_word(&args[i], intval); } break; + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + if (!mjs_is_string(arg)) { + ret = MJS_TYPE_ERROR; + mjs_prepend_errorf( + mjs, ret, "actual arg #%d is not a string (the type idx is: %s)", + i, mjs_typeof(arg)); + goto clean; + } + argvs[i] = arg; + argvmgstr[i].p = mjs_get_string(mjs, &argvs[i], &argvmgstr[i].len); + /* + * String argument should be saved separately in order to support + * short strings (which are packed into mjs_val_t itself) + */ + ffi_set_ptr(&args[i], (void *) &argvmgstr[i]); + break; + } case MJS_FFI_CTYPE_BOOL: { int intval = 0; if (mjs_is_number(arg)) { @@ -1006,6 +1034,7 @@ MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig, case MJS_FFI_CTYPE_BOOL: case MJS_FFI_CTYPE_VOID_PTR: case MJS_FFI_CTYPE_CHAR_PTR: + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: case MJS_FFI_CTYPE_DOUBLE: case MJS_FFI_CTYPE_FLOAT: /* Do nothing */ diff --git a/mjs/src/mjs_ffi.h b/mjs/src/mjs_ffi.h index dc08539..3715211 100644 --- a/mjs/src/mjs_ffi.h +++ b/mjs/src/mjs_ffi.h @@ -7,8 +7,8 @@ #define MJS_FFI_H_ #include "mjs/src/ffi/ffi.h" -#include "mjs/src/mjs_internal.h" #include "mjs/src/mjs_ffi_public.h" +#include "mjs/src/mjs_internal.h" #if defined(__cplusplus) extern "C" { @@ -29,6 +29,7 @@ enum mjs_ffi_ctype { MJS_FFI_CTYPE_FLOAT, MJS_FFI_CTYPE_CHAR_PTR, MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, MJS_FFI_CTYPE_INVALID, }; typedef uint8_t mjs_ffi_ctype_t; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 5533873..7302f9f 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -899,6 +899,7 @@ void *stub_dlsym(void *handle, const char *name) { if (strcmp(name, "ffi_test_cb_iiui2") == 0) return (void *) ffi_test_cb_iiui2; if (strcmp(name, "ffi_test_cb_viiiiiu") == 0) return (void *) ffi_test_cb_viiiiiu; if (strcmp(name, "ffi_test_inbuf") == 0) return (void *) ffi_test_inbuf; + if (strcmp(name, "mg_vcasecmp") == 0) return (void *) mg_vcasecmp; if (strcmp(name, "malloc") == 0) return (void *) malloc; if (strcmp(name, "calloc") == 0) return (void *) calloc; if (strcmp(name, "free") == 0) return (void *) free; @@ -1174,6 +1175,15 @@ const char *test_call_ffi(struct mjs *mjs) { ASSERT_EQ(mjs_exec(mjs, "ffi_test_s1s('\\x01')", &res), MJS_TYPE_ERROR); ASSERT_STREQ(mjs->error_msg, "failed to call FFIed function: non-ffi-callable value"); + /* Test struct mg_str * FFI, long and short strings */ + ASSERT_EQ(mjs_exec(mjs, "let mg_vcasecmp = ffi('int mg_vcasecmp(struct mg_str *, char *)');", &res), MJS_OK); + ASSERT_EQ(mjs_exec(mjs, "mg_vcasecmp('foobar', 'FooBar') === 0;", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + ASSERT_EQ(mjs_exec(mjs, "mg_vcasecmp('foobar', 'Foo') !== 0;", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + ASSERT_EQ(mjs_exec(mjs, "mg_vcasecmp('a', 'A') === 0;", &res), MJS_OK); + ASSERT_EQ(mjs_get_bool(mjs, res), 1); + /* Test the ability to pass char buffers to C */ { size_t len; From 9154431019dd825467f8585825ed9889fa4b9e1e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 23 Nov 2017 12:40:12 +0300 Subject: [PATCH 107/265] Compatibility with LwIP 2.0 2.0 redefined LWIP_VERSION in a way that is no longer compatible with use by preprocessor (boo). also, tcp_pcb.acked is gone, but we only use it for debug, so it doesn't matter. PUBLISHED_FROM=776f90a08bd5024fa8a61dae257af6c60ec6710d --- common/platforms/lwip/mg_lwip_net_if.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index e05f4d2..7c0b9bf 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -11,7 +11,7 @@ #include #include #include -#if LWIP_VERSION >= 0x01050000 +#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105 #include /* For tcp_seg */ #else #include @@ -270,7 +270,7 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc, * Lwip included in the SDKs for nRF5x chips has different type for the * callback of `udp_recv()` */ -#if LWIP_VERSION >= 0x01050000 +#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105 static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) #else @@ -288,7 +288,7 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, return; } union socket_address *sa = (union socket_address *) sap->payload; -#if LWIP_VERSION >= 0x01050000 +#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105 sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr; #else sa->sin.sin_addr.s_addr = addr->addr; @@ -505,8 +505,8 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf)); size_t unsent, unacked; if (len == 0) { - DBG(("%p no buf avail %u %u %u %p %p", tpcb, tpcb->acked, tpcb->snd_buf, - tpcb->snd_queuelen, tpcb->unsent, tpcb->unacked)); + DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen, + tpcb->unsent, tpcb->unacked)); tcpip_callback(tcp_output_tcpip, tpcb); ctx->ret = 0; return; From d6c06a61743d6748ac167adb75da3d81d5d62070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Thu, 23 Nov 2017 11:09:47 +0000 Subject: [PATCH 108/265] Document mg_match_prefix PUBLISHED_FROM=b85fe1ee1e7bae4528c1240d8531c410728d0709 --- common/str_util.h | 18 ++++++++++++++++-- mjs.c | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/common/str_util.h b/common/str_util.h index 0745a3c..dccd0d2 100644 --- a/common/str_util.h +++ b/common/str_util.h @@ -125,10 +125,24 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, /* * Matches 0-terminated string (mg_match_prefix) or string with given length - * mg_match_prefix_n against a glob pattern. - * + * mg_match_prefix_n against a glob pattern. Glob syntax: + * ``` + * - * matches zero or more characters until a slash character / + * - ** matches zero or more characters + * - ? Matches exactly one character which is not a slash / + * - | or , divides alternative patterns + * - any other character matches itself + * ``` * Match is case-insensitive. Returns number of bytes matched, or -1 if no * match. + * Examples: + * ``` + * mg_match_prefix("a*f", len, "abcdefgh") == 6 + * mg_match_prefix("a*f", len, "abcdexgh") == -1 + * mg_match_prefix("a*f|de*,xy", len, "defgh") == 5 + * mg_match_prefix("?*", len, "abc") == 3 + * mg_match_prefix("?*", len, "") == -1 + * ``` */ int mg_match_prefix(const char *pattern, int pattern_len, const char *str); int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); diff --git a/mjs.c b/mjs.c index 6ecd2c0..f1a0570 100644 --- a/mjs.c +++ b/mjs.c @@ -1888,10 +1888,24 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, /* * Matches 0-terminated string (mg_match_prefix) or string with given length - * mg_match_prefix_n against a glob pattern. - * + * mg_match_prefix_n against a glob pattern. Glob syntax: + * ``` + * - * matches zero or more characters until a slash character / + * - ** matches zero or more characters + * - ? Matches exactly one character which is not a slash / + * - | or , divides alternative patterns + * - any other character matches itself + * ``` * Match is case-insensitive. Returns number of bytes matched, or -1 if no * match. + * Examples: + * ``` + * mg_match_prefix("a*f", len, "abcdefgh") == 6 + * mg_match_prefix("a*f", len, "abcdexgh") == -1 + * mg_match_prefix("a*f|de*,xy", len, "defgh") == 5 + * mg_match_prefix("?*", len, "abc") == 3 + * mg_match_prefix("?*", len, "") == -1 + * ``` */ int mg_match_prefix(const char *pattern, int pattern_len, const char *str); int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); From db0e2d696be94df098ca42e1e417cf0c500014a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sun, 26 Nov 2017 11:22:46 +0000 Subject: [PATCH 109/265] Fail on invalid input Partially addresses https://github.com/cesanta/mjs/issues/54 PUBLISHED_FROM=0ac82d348ccbc5e4e671c1aaa131b3dae366a3a9 --- mjs.c | 11 +++++++---- mjs/Makefile | 2 +- mjs/src/mjs_tok.c | 10 ++++++---- mjs/src/mjs_tok.h | 1 + mjs/tests/unit_test.c | 2 ++ 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/mjs.c b/mjs.c index f1a0570..31d8ffa 100644 --- a/mjs.c +++ b/mjs.c @@ -4232,6 +4232,7 @@ struct pstate { enum { TOK_EOF, + TOK_INVALID, TOK_COLON, TOK_SEMICOLON, @@ -13780,7 +13781,7 @@ MJS_PRIVATE void pinit(const char *file_name, const char *buf, // We're not relying on the target libc ctype, as it may incorrectly // handle negative arguments, e.g. isspace(-1). static int mjs_is_space(int c) { - return c == ' ' || c == '\r' || c == '\n' || c == '\t'; + return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f' || c == '\v'; } MJS_PRIVATE int mjs_is_digit(int c) { @@ -13964,13 +13965,15 @@ static int ptranslate(int tok) { } MJS_PRIVATE int pnext(struct pstate *p) { - int tmp, tok = TOK_EOF; + int tmp, tok = TOK_INVALID; skip_spaces_and_comments(p); p->tok.ptr = p->pos; p->tok.len = 1; - if (mjs_is_digit(p->pos[0])) { + if (p->pos[0] == '\0') { + tok = TOK_EOF; + } if (mjs_is_digit(p->pos[0])) { tok = getnum(p); } else if (p->pos[0] == '\'' || p->pos[0] == '"') { tok = getstr(p); @@ -14002,7 +14005,7 @@ MJS_PRIVATE int pnext(struct pstate *p) { tok = tmp; } if (p->pos[0] != '\0') p->pos++; - LOG(LL_VERBOSE_DEBUG, (" --> [%.*s]", p->tok.len, p->tok.ptr)); + LOG(LL_VERBOSE_DEBUG, (" --> %d [%.*s]", tok, p->tok.len, p->tok.ptr)); p->prev_tok = p->tok.tok; p->tok.tok = ptranslate(tok); return p->tok.tok; diff --git a/mjs/Makefile b/mjs/Makefile index d3fa3f0..98fc47f 100644 --- a/mjs/Makefile +++ b/mjs/Makefile @@ -131,7 +131,7 @@ TEST_VARIANTS = define compile_test $(BUILD_DIR)/unit_test_$1: tests/unit_test.c mjs.c $(TESTUTIL_FILES) $(BUILD_DIR) @echo BUILDING $$@ with $2[$3], flags: "'$4'" - $(RD) --entrypoint $3 $2 $$(COMMON_TEST_FLAGS) $4 -lm -o $$@ + $(RD) --entrypoint $3 $2 $$(COMMON_TEST_FLAGS) $4 -ldl -lm -o $$@ $(RD) --entrypoint ./$$@ $2 TEST_VARIANTS += $(BUILD_DIR)/unit_test_$1 diff --git a/mjs/src/mjs_tok.c b/mjs/src/mjs_tok.c index 11d8488..c1d9d26 100644 --- a/mjs/src/mjs_tok.c +++ b/mjs/src/mjs_tok.c @@ -22,7 +22,7 @@ MJS_PRIVATE void pinit(const char *file_name, const char *buf, // We're not relying on the target libc ctype, as it may incorrectly // handle negative arguments, e.g. isspace(-1). static int mjs_is_space(int c) { - return c == ' ' || c == '\r' || c == '\n' || c == '\t'; + return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f' || c == '\v'; } MJS_PRIVATE int mjs_is_digit(int c) { @@ -206,13 +206,15 @@ static int ptranslate(int tok) { } MJS_PRIVATE int pnext(struct pstate *p) { - int tmp, tok = TOK_EOF; + int tmp, tok = TOK_INVALID; skip_spaces_and_comments(p); p->tok.ptr = p->pos; p->tok.len = 1; - if (mjs_is_digit(p->pos[0])) { + if (p->pos[0] == '\0') { + tok = TOK_EOF; + } if (mjs_is_digit(p->pos[0])) { tok = getnum(p); } else if (p->pos[0] == '\'' || p->pos[0] == '"') { tok = getstr(p); @@ -244,7 +246,7 @@ MJS_PRIVATE int pnext(struct pstate *p) { tok = tmp; } if (p->pos[0] != '\0') p->pos++; - LOG(LL_VERBOSE_DEBUG, (" --> [%.*s]", p->tok.len, p->tok.ptr)); + LOG(LL_VERBOSE_DEBUG, (" --> %d [%.*s]", tok, p->tok.len, p->tok.ptr)); p->prev_tok = p->tok.tok; p->tok.tok = ptranslate(tok); return p->tok.tok; diff --git a/mjs/src/mjs_tok.h b/mjs/src/mjs_tok.h index 82afc3a..c781976 100644 --- a/mjs/src/mjs_tok.h +++ b/mjs/src/mjs_tok.h @@ -35,6 +35,7 @@ struct pstate { enum { TOK_EOF, + TOK_INVALID, TOK_COLON, TOK_SEMICOLON, diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 7302f9f..aeb17f2 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -3602,6 +3602,8 @@ const char *test_lib_math(struct mjs *mjs) { const char *test_parser(struct mjs *mjs) { mjs_val_t res = MJS_UNDEFINED; mjs_own(mjs, &res); + CHECK_NUMERIC("\f\v\r\n\t1", 1); + ASSERT_EQ(mjs_exec(mjs, "\a1", &res), MJS_SYNTAX_ERROR); CHECK_NUMERIC("1,2,3", 3); CHECK_NUMERIC("let f = function(x){return x;}; f(1),f(2),f(3)", 3); ASSERT_EXEC_OK(mjs_exec(mjs, ";", &res)); From 618eb4241f28444e44da1a5122493bed29465be7 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 29 Nov 2017 00:15:23 +0200 Subject: [PATCH 110/265] Fix crash on remainder < 1 PUBLISHED_FROM=be9c13e4dd57db8ca7e56493f460896ba41be099 --- mjs.c | 5 +++++ mjs/src/mjs_exec.c | 5 +++++ mjs/tests/unit_test.c | 1 + 3 files changed, 11 insertions(+) diff --git a/mjs.c b/mjs.c index 31d8ffa..f8b7081 100644 --- a/mjs.c +++ b/mjs.c @@ -8614,6 +8614,11 @@ static double do_arith_op(double da, double db, int op) { return (double) MJS_TAG_NAN; } case TOK_REM: + /* + * TODO(dfrank): probably support remainder operation as it is in JS + * (which works with non-integer divisor). + */ + db = (int) db; if (db != 0) { return (double) ((int64_t) da % (int64_t) db); } else { diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index d4d46d2..a30b6cb 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -94,6 +94,11 @@ static double do_arith_op(double da, double db, int op) { return (double) MJS_TAG_NAN; } case TOK_REM: + /* + * TODO(dfrank): probably support remainder operation as it is in JS + * (which works with non-integer divisor). + */ + db = (int) db; if (db != 0) { return (double) ((int64_t) da % (int64_t) db); } else { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index aeb17f2..98b25a7 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -135,6 +135,7 @@ const char *test_arithmetic(struct mjs *mjs) { CHECK_NUMERIC("200*50", 10000); CHECK_NUMERIC("200/50", 4); CHECK_NUMERIC("200 % 21", 11); + CHECK_NUMERIC("200 % 0.999", MJS_TAG_NAN); CHECK_NUMERIC("100 << 3", 800); CHECK_NUMERIC("(0-14) >> 2", -4); CHECK_NUMERIC("(0-14) >>> 2", 1073741820); From d2e169fb957dd5288774624eeeb3ba279042a062 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 1 Dec 2017 23:36:18 +0200 Subject: [PATCH 111/265] Handle misplaced 'continue' properly PUBLISHED_FROM=a0e1bc55443be5ec1553a209db2d430fe5d66b4b --- mjs.c | 39 +++++++++++++++++++++++---------------- mjs/src/mjs_exec.c | 39 +++++++++++++++++++++++---------------- mjs/tests/unit_test.c | 15 +++++++++++++++ 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/mjs.c b/mjs.c index f8b7081..3d56657 100644 --- a/mjs.c +++ b/mjs.c @@ -9370,28 +9370,35 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { break; } case OP_CONTINUE: { - /* restore scope index */ - size_t scopes_len = mjs_get_int(mjs, *vptr(&mjs->loop_addresses, -3)); - assert(mjs_stack_size(&mjs->scopes) >= scopes_len); - mjs->scopes.len = scopes_len * sizeof(mjs_val_t); + if (mjs_stack_size(&mjs->loop_addresses) >= 3) { + size_t scopes_len = mjs_get_int(mjs, *vptr(&mjs->loop_addresses, -3)); + assert(mjs_stack_size(&mjs->scopes) >= scopes_len); + mjs->scopes.len = scopes_len * sizeof(mjs_val_t); - /* jump to "continue" address */ - i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; + /* jump to "continue" address */ + i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; + } else { + mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'continue'"); + } } break; case OP_BREAK: { - size_t scopes_len; - /* drop "continue" address */ - mjs_pop_val(&mjs->loop_addresses); + if (mjs_stack_size(&mjs->loop_addresses) >= 3) { + size_t scopes_len; + /* drop "continue" address */ + mjs_pop_val(&mjs->loop_addresses); - /* pop "break" address and jump to it */ - i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; + /* pop "break" address and jump to it */ + i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; - /* restore scope index */ - scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); - assert(mjs_stack_size(&mjs->scopes) >= scopes_len); - mjs->scopes.len = scopes_len * sizeof(mjs_val_t); + /* restore scope index */ + scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); + assert(mjs_stack_size(&mjs->scopes) >= scopes_len); + mjs->scopes.len = scopes_len * sizeof(mjs_val_t); - LOG(LL_VERBOSE_DEBUG, ("BREAKING TO %d", (int) i + 1)); + LOG(LL_VERBOSE_DEBUG, ("BREAKING TO %d", (int) i + 1)); + } else { + mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'break'"); + } } break; case OP_NOP: break; diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index a30b6cb..7d37172 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -850,28 +850,35 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { break; } case OP_CONTINUE: { - /* restore scope index */ - size_t scopes_len = mjs_get_int(mjs, *vptr(&mjs->loop_addresses, -3)); - assert(mjs_stack_size(&mjs->scopes) >= scopes_len); - mjs->scopes.len = scopes_len * sizeof(mjs_val_t); + if (mjs_stack_size(&mjs->loop_addresses) >= 3) { + size_t scopes_len = mjs_get_int(mjs, *vptr(&mjs->loop_addresses, -3)); + assert(mjs_stack_size(&mjs->scopes) >= scopes_len); + mjs->scopes.len = scopes_len * sizeof(mjs_val_t); - /* jump to "continue" address */ - i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; + /* jump to "continue" address */ + i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1; + } else { + mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'continue'"); + } } break; case OP_BREAK: { - size_t scopes_len; - /* drop "continue" address */ - mjs_pop_val(&mjs->loop_addresses); + if (mjs_stack_size(&mjs->loop_addresses) >= 3) { + size_t scopes_len; + /* drop "continue" address */ + mjs_pop_val(&mjs->loop_addresses); - /* pop "break" address and jump to it */ - i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; + /* pop "break" address and jump to it */ + i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1; - /* restore scope index */ - scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); - assert(mjs_stack_size(&mjs->scopes) >= scopes_len); - mjs->scopes.len = scopes_len * sizeof(mjs_val_t); + /* restore scope index */ + scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)); + assert(mjs_stack_size(&mjs->scopes) >= scopes_len); + mjs->scopes.len = scopes_len * sizeof(mjs_val_t); - LOG(LL_VERBOSE_DEBUG, ("BREAKING TO %d", (int) i + 1)); + LOG(LL_VERBOSE_DEBUG, ("BREAKING TO %d", (int) i + 1)); + } else { + mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'break'"); + } } break; case OP_NOP: break; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 98b25a7..5879377 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -1659,6 +1659,20 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { return NULL; } +const char *test_misplaced_loop_constructs(struct mjs *mjs) { + mjs_val_t res = MJS_UNDEFINED; + mjs_own(mjs, &res); + + ASSERT_EQ(mjs_exec(mjs, "continue;", &res), MJS_SYNTAX_ERROR); + ASSERT_STREQ(mjs->error_msg, "misplaced 'continue'"); + + ASSERT_EQ(mjs_exec(mjs, "break;", &res), MJS_SYNTAX_ERROR); + ASSERT_STREQ(mjs->error_msg, "misplaced 'break'"); + + mjs_disown(mjs, &res); + return NULL; +} + const char *test_errors(struct mjs *mjs) { mjs_val_t res = MJS_UNDEFINED; mjs_own(mjs, &res); @@ -3625,6 +3639,7 @@ static const char *run_all_tests(const char *filter, double *total_elapsed) { RUN_TEST_MJS(test_comparison); RUN_TEST_MJS(test_logic); RUN_TEST_MJS(test_errors); + RUN_TEST_MJS(test_misplaced_loop_constructs); RUN_TEST_MJS(test_this); RUN_TEST_MJS(test_while); RUN_TEST_MJS(test_for_loop); From a7c18fa6d449c6a52f5993ab6d779d7e454db915 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 01:05:55 +0200 Subject: [PATCH 112/265] Cleanup loop_addresses on error PUBLISHED_FROM=90ba7862800559391225e097584e3a39f4fb8fa9 --- mjs.c | 2 ++ mjs/src/mjs_exec.c | 2 ++ mjs/tests/unit_test.c | 21 ++++++--------------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/mjs.c b/mjs.c index 3d56657..c25684c 100644 --- a/mjs.c +++ b/mjs.c @@ -9016,6 +9016,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int call_stack_len = mjs->call_stack.len; int arg_stack_len = mjs->arg_stack.len; int scopes_len = mjs->scopes.len; + int loop_addresses_len = mjs->loop_addresses.len; size_t start_off = off; const uint8_t *code; @@ -9422,6 +9423,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { mjs->call_stack.len = call_stack_len; mjs->arg_stack.len = arg_stack_len; mjs->scopes.len = scopes_len; + mjs->loop_addresses.len = loop_addresses_len; /* script will evaluate to `undefined` */ mjs_push(mjs, MJS_UNDEFINED); diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 7d37172..74915f7 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -496,6 +496,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { int call_stack_len = mjs->call_stack.len; int arg_stack_len = mjs->arg_stack.len; int scopes_len = mjs->scopes.len; + int loop_addresses_len = mjs->loop_addresses.len; size_t start_off = off; const uint8_t *code; @@ -902,6 +903,7 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { mjs->call_stack.len = call_stack_len; mjs->arg_stack.len = arg_stack_len; mjs->scopes.len = scopes_len; + mjs->loop_addresses.len = loop_addresses_len; /* script will evaluate to `undefined` */ mjs_push(mjs, MJS_UNDEFINED); diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 5879377..3423f4d 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -1659,20 +1659,6 @@ const char *test_call_ffi_cb_err(struct mjs *mjs) { return NULL; } -const char *test_misplaced_loop_constructs(struct mjs *mjs) { - mjs_val_t res = MJS_UNDEFINED; - mjs_own(mjs, &res); - - ASSERT_EQ(mjs_exec(mjs, "continue;", &res), MJS_SYNTAX_ERROR); - ASSERT_STREQ(mjs->error_msg, "misplaced 'continue'"); - - ASSERT_EQ(mjs_exec(mjs, "break;", &res), MJS_SYNTAX_ERROR); - ASSERT_STREQ(mjs->error_msg, "misplaced 'break'"); - - mjs_disown(mjs, &res); - return NULL; -} - const char *test_errors(struct mjs *mjs) { mjs_val_t res = MJS_UNDEFINED; mjs_own(mjs, &res); @@ -1723,6 +1709,12 @@ const char *test_errors(struct mjs *mjs) { ASSERT_EQ(mjs_exec(mjs, "let s = 'foo'; s += 12", &res), MJS_TYPE_ERROR); ASSERT_STREQ(mjs->error_msg, "implicit type conversion is prohibited"); + ASSERT_EQ(mjs_exec(mjs, "continue;", &res), MJS_SYNTAX_ERROR); + ASSERT_STREQ(mjs->error_msg, "misplaced 'continue'"); + + ASSERT_EQ(mjs_exec(mjs, "break;", &res), MJS_SYNTAX_ERROR); + ASSERT_STREQ(mjs->error_msg, "misplaced 'break'"); + ASSERT_EQ(mjs_exec(mjs, "load('foo/bar/bazzz')", &res), MJS_FILE_READ_ERROR); { const char *rs = "failed to exec file \"foo/bar/bazzz\": failed to read file \"foo/bar/bazzz\""; @@ -3639,7 +3631,6 @@ static const char *run_all_tests(const char *filter, double *total_elapsed) { RUN_TEST_MJS(test_comparison); RUN_TEST_MJS(test_logic); RUN_TEST_MJS(test_errors); - RUN_TEST_MJS(test_misplaced_loop_constructs); RUN_TEST_MJS(test_this); RUN_TEST_MJS(test_while); RUN_TEST_MJS(test_for_loop); From 19648c1f22ded2d726912f4e1ff1380416a25042 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 01:00:17 +0200 Subject: [PATCH 113/265] Handle invalid value in for-in loop PUBLISHED_FROM=4ba51681db5cfabe0b3b3dd8c84524b78be99960 --- mjs.c | 15 ++++++++++----- mjs/src/mjs_exec.c | 15 ++++++++++----- mjs/tests/unit_test.c | 3 +++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/mjs.c b/mjs.c index c25684c..9f3dd8f 100644 --- a/mjs.c +++ b/mjs.c @@ -9210,11 +9210,16 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { */ mjs_val_t *iterator = vptr(&mjs->stack, -1); mjs_val_t obj = *vptr(&mjs->stack, -2); - mjs_val_t var_name = *vptr(&mjs->stack, -3); - mjs_val_t key = mjs_next(mjs, obj, iterator); - if (key != MJS_UNDEFINED) { - mjs_val_t scope = mjs_find_scope(mjs, var_name); - mjs_set_v(mjs, scope, var_name, key); + if (mjs_is_object(obj)) { + mjs_val_t var_name = *vptr(&mjs->stack, -3); + mjs_val_t key = mjs_next(mjs, obj, iterator); + if (key != MJS_UNDEFINED) { + mjs_val_t scope = mjs_find_scope(mjs, var_name); + mjs_set_v(mjs, scope, var_name, key); + } + } else { + mjs_set_errorf(mjs, MJS_TYPE_ERROR, + "can't iterate over non-object value"); } break; } diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 74915f7..a73d2ce 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -690,11 +690,16 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { */ mjs_val_t *iterator = vptr(&mjs->stack, -1); mjs_val_t obj = *vptr(&mjs->stack, -2); - mjs_val_t var_name = *vptr(&mjs->stack, -3); - mjs_val_t key = mjs_next(mjs, obj, iterator); - if (key != MJS_UNDEFINED) { - mjs_val_t scope = mjs_find_scope(mjs, var_name); - mjs_set_v(mjs, scope, var_name, key); + if (mjs_is_object(obj)) { + mjs_val_t var_name = *vptr(&mjs->stack, -3); + mjs_val_t key = mjs_next(mjs, obj, iterator); + if (key != MJS_UNDEFINED) { + mjs_val_t scope = mjs_find_scope(mjs, var_name); + mjs_set_v(mjs, scope, var_name, key); + } + } else { + mjs_set_errorf(mjs, MJS_TYPE_ERROR, + "can't iterate over non-object value"); } break; } diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 3423f4d..fb7a241 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -1727,6 +1727,9 @@ const char *test_errors(struct mjs *mjs) { ASSERT_STREQ(mjs->error_msg, rs); } + ASSERT_EQ(mjs_exec(mjs, "for (let i in 0) {}", &res), MJS_TYPE_ERROR); + ASSERT_STREQ(mjs->error_msg, "can't iterate over non-object value"); + mjs_disown(mjs, &res); return NULL; } From bb92a2f4250893322b5a8f650c6f7e3f5fa34704 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 01:36:02 +0200 Subject: [PATCH 114/265] Make phony targets phony PUBLISHED_FROM=1b2dcd3bec05575c1f5eb72c3ee4caa4f728923f --- mjs/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mjs/Makefile b/mjs/Makefile index 98fc47f..4f3ae4f 100644 --- a/mjs/Makefile +++ b/mjs/Makefile @@ -22,6 +22,8 @@ CFLAGS += -lm -W -Wall -g $(MFLAGS) COMMON_CFLAGS = -DCS_MMAP ASAN_CFLAGS = -fsanitize=address +.PHONY: all test test_full difftest ci-test + VERBOSE ?= ifeq ($(VERBOSE),1) Q := From b334c638bd71ab9d2667108a28b4fc6e04923a98 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 18:10:46 +0200 Subject: [PATCH 115/265] Cleanup loop addresses properly PUBLISHED_FROM=7e4ab4c395b79d86e85f1cf9cd1abe3b29419cab --- mjs.c | 48 +++++++++++++++++++++++++++++++------------ mjs/src/mjs_core.c | 19 +++++++++-------- mjs/src/mjs_core.h | 1 + mjs/src/mjs_exec.c | 28 ++++++++++++++++++++----- mjs/tests/unit_test.c | 26 +++++++++++++++++++++++ 5 files changed, 96 insertions(+), 26 deletions(-) diff --git a/mjs.c b/mjs.c index 9f3dd8f..c3f7db4 100644 --- a/mjs.c +++ b/mjs.c @@ -2927,6 +2927,7 @@ enum mjs_type { enum mjs_call_stack_frame_item { CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX, /* TOS */ + CALL_STACK_FRAME_ITEM_LOOP_ADDR_IDX, CALL_STACK_FRAME_ITEM_SCOPE_IDX, CALL_STACK_FRAME_ITEM_RETURN_ADDR, CALL_STACK_FRAME_ITEM_THIS, @@ -8310,14 +8311,17 @@ MJS_PRIVATE void mjs_gen_stack_trace(struct mjs *mjs, size_t offset) { mjs_append_stack_trace_line(mjs, offset); while (mjs->call_stack.len >= sizeof(mjs_val_t) * CALL_STACK_FRAME_ITEMS_CNT) { - /* pop retval_stack_idx */ - mjs_pop_val(&mjs->call_stack); - /* pop scope_index */ - mjs_pop_val(&mjs->call_stack); - /* pop return_address and set current offset to it */ - offset = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); - /* pop this object */ - mjs_pop_val(&mjs->call_stack); + int i; + + /* set current offset to it to the offset stored in the frame */ + offset = mjs_get_int( + mjs, *vptr(&mjs->call_stack, -1 - CALL_STACK_FRAME_ITEM_RETURN_ADDR)); + + /* pop frame from the call stack */ + for (i = 0; i < CALL_STACK_FRAME_ITEMS_CNT; i++) { + mjs_pop_val(&mjs->call_stack); + } + mjs_append_stack_trace_line(mjs, offset); } } @@ -8551,12 +8555,19 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, mjs_val_t retval_stack_idx) { /* Pop `this` value, and apply it */ mjs_val_t this_obj = mjs_pop_val(&mjs->arg_stack); + + /* + * NOTE: the layout is described by enum mjs_call_stack_frame_item + */ push_mjs_val(&mjs->call_stack, mjs->vals.this_obj); mjs->vals.this_obj = this_obj; push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) offset)); push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); + push_mjs_val( + &mjs->call_stack, + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->loop_addresses))); push_mjs_val(&mjs->call_stack, retval_stack_idx); } @@ -8564,23 +8575,32 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, * Restores call stack frame. Returns the return address. */ static size_t call_stack_restore_frame(struct mjs *mjs) { - size_t retval_stack_idx, return_address, scope_index; + size_t retval_stack_idx, return_address, scope_index, loop_addr_index; assert(mjs_stack_size(&mjs->call_stack) >= CALL_STACK_FRAME_ITEMS_CNT); + /* + * NOTE: the layout is described by enum mjs_call_stack_frame_item + */ retval_stack_idx = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); + loop_addr_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); scope_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); return_address = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); mjs->vals.this_obj = mjs_pop_val(&mjs->call_stack); - // Remove created scopes + /* Remove created scopes */ while (mjs_stack_size(&mjs->scopes) > scope_index) { mjs_pop_val(&mjs->scopes); } - // Shrink stack, leave return value on top + /* Remove loop addresses */ + while (mjs_stack_size(&mjs->loop_addresses) > loop_addr_index) { + mjs_pop_val(&mjs->loop_addresses); + } + + /* Shrink stack, leave return value on top */ mjs->stack.len = retval_stack_idx * sizeof(mjs_val_t); - // Jump to the return address + /* Jump to the return address */ return return_address; } @@ -9328,7 +9348,9 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { if (mjs_stack_size(&mjs->call_stack) < CALL_STACK_FRAME_ITEMS_CNT) { mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "cannot return"); } else { - size_t retval_pos = mjs_get_int(mjs, *vptr(&mjs->call_stack, -1)); + size_t retval_pos = mjs_get_int( + mjs, *vptr(&mjs->call_stack, + -1 - CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX)); *vptr(&mjs->stack, retval_pos - 1) = mjs_pop(mjs); } // LOG(LL_INFO, ("AFTER SETRETVAL")); diff --git a/mjs/src/mjs_core.c b/mjs/src/mjs_core.c index d365c02..548c7ad 100644 --- a/mjs/src/mjs_core.c +++ b/mjs/src/mjs_core.c @@ -266,14 +266,17 @@ MJS_PRIVATE void mjs_gen_stack_trace(struct mjs *mjs, size_t offset) { mjs_append_stack_trace_line(mjs, offset); while (mjs->call_stack.len >= sizeof(mjs_val_t) * CALL_STACK_FRAME_ITEMS_CNT) { - /* pop retval_stack_idx */ - mjs_pop_val(&mjs->call_stack); - /* pop scope_index */ - mjs_pop_val(&mjs->call_stack); - /* pop return_address and set current offset to it */ - offset = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); - /* pop this object */ - mjs_pop_val(&mjs->call_stack); + int i; + + /* set current offset to it to the offset stored in the frame */ + offset = mjs_get_int( + mjs, *vptr(&mjs->call_stack, -1 - CALL_STACK_FRAME_ITEM_RETURN_ADDR)); + + /* pop frame from the call stack */ + for (i = 0; i < CALL_STACK_FRAME_ITEMS_CNT; i++) { + mjs_pop_val(&mjs->call_stack); + } + mjs_append_stack_trace_line(mjs, offset); } } diff --git a/mjs/src/mjs_core.h b/mjs/src/mjs_core.h index aab7a3a..eefea93 100644 --- a/mjs/src/mjs_core.h +++ b/mjs/src/mjs_core.h @@ -38,6 +38,7 @@ enum mjs_type { enum mjs_call_stack_frame_item { CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX, /* TOS */ + CALL_STACK_FRAME_ITEM_LOOP_ADDR_IDX, CALL_STACK_FRAME_ITEM_SCOPE_IDX, CALL_STACK_FRAME_ITEM_RETURN_ADDR, CALL_STACK_FRAME_ITEM_THIS, diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index a73d2ce..99bd66f 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -31,12 +31,19 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, mjs_val_t retval_stack_idx) { /* Pop `this` value, and apply it */ mjs_val_t this_obj = mjs_pop_val(&mjs->arg_stack); + + /* + * NOTE: the layout is described by enum mjs_call_stack_frame_item + */ push_mjs_val(&mjs->call_stack, mjs->vals.this_obj); mjs->vals.this_obj = this_obj; push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) offset)); push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes))); + push_mjs_val( + &mjs->call_stack, + mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->loop_addresses))); push_mjs_val(&mjs->call_stack, retval_stack_idx); } @@ -44,23 +51,32 @@ static void call_stack_push_frame(struct mjs *mjs, size_t offset, * Restores call stack frame. Returns the return address. */ static size_t call_stack_restore_frame(struct mjs *mjs) { - size_t retval_stack_idx, return_address, scope_index; + size_t retval_stack_idx, return_address, scope_index, loop_addr_index; assert(mjs_stack_size(&mjs->call_stack) >= CALL_STACK_FRAME_ITEMS_CNT); + /* + * NOTE: the layout is described by enum mjs_call_stack_frame_item + */ retval_stack_idx = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); + loop_addr_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); scope_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); return_address = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack)); mjs->vals.this_obj = mjs_pop_val(&mjs->call_stack); - // Remove created scopes + /* Remove created scopes */ while (mjs_stack_size(&mjs->scopes) > scope_index) { mjs_pop_val(&mjs->scopes); } - // Shrink stack, leave return value on top + /* Remove loop addresses */ + while (mjs_stack_size(&mjs->loop_addresses) > loop_addr_index) { + mjs_pop_val(&mjs->loop_addresses); + } + + /* Shrink stack, leave return value on top */ mjs->stack.len = retval_stack_idx * sizeof(mjs_val_t); - // Jump to the return address + /* Jump to the return address */ return return_address; } @@ -808,7 +824,9 @@ MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) { if (mjs_stack_size(&mjs->call_stack) < CALL_STACK_FRAME_ITEMS_CNT) { mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "cannot return"); } else { - size_t retval_pos = mjs_get_int(mjs, *vptr(&mjs->call_stack, -1)); + size_t retval_pos = mjs_get_int( + mjs, *vptr(&mjs->call_stack, + -1 - CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX)); *vptr(&mjs->stack, retval_pos - 1) = mjs_pop(mjs); } // LOG(LL_INFO, ("AFTER SETRETVAL")); diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index fb7a241..5e0defa 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2170,6 +2170,19 @@ const char *test_for_loop(struct mjs *mjs) { ), &res)); ASSERT_STREQ(mjs_get_cstring(mjs, &res), "_0:|-4|-3.....|-1|0_1:|-3|-2.....|0|1_3:|-1|0.....|2|3_4:|0|1.....|3|4_5:|1|2.....|4|5_6:|2|3.....|5|6_7:|3|4.....|6|7_8:|4|5.....|7|8_9:|5|6.....|8|9"); + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + function foo() { + for (i = 0; i < 10; i++) { + if (i === 2) { + return true; + } + } + } + foo(); + ), &res)); + ASSERT_EQ(mjs->loop_addresses.len, 0); + mjs_disown(mjs, &res); return NULL; @@ -2209,6 +2222,19 @@ const char *test_for_in_loop(struct mjs *mjs) { //ASSERT_STREQ(mjs_get_cstring(mjs, &res), "_five:5_baz:3_bar:2"); #endif + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + function foo() { + let o = ({foo: 1, bar: 2, baz: 3, four: 4, five: 5}); let s=""; + for (let k in o) { + return true; + } + } + foo(); + ), &res)); + ASSERT_EQ(mjs->loop_addresses.len, 0); + + mjs_disown(mjs, &res); return NULL; From 3a5b1ce4e9c4ccc172900fc4a206a33ef057586f Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 19:58:47 +0200 Subject: [PATCH 116/265] Fix return without a value PUBLISHED_FROM=dd63c4a578578ad1530f28cc8a11b819055f03d2 --- mjs.c | 4 +++- mjs/src/mjs_parser.c | 4 +++- mjs/tests/unit_test.c | 9 +++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index c3f7db4..d5dd51d 100644 --- a/mjs.c +++ b/mjs.c @@ -12981,7 +12981,9 @@ static mjs_err_t parse_if(struct pstate *p) { static mjs_err_t parse_return(struct pstate *p) { EXPECT(p, TOK_KEYWORD_RETURN); - parse_expr(p); + if (parse_expr(p) != MJS_OK) { + emit_byte(p, OP_PUSH_UNDEF); + } emit_byte(p, OP_SETRETVAL); emit_byte(p, OP_RETURN); return MJS_OK; diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index c50744d..7ab130a 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -841,7 +841,9 @@ static mjs_err_t parse_if(struct pstate *p) { static mjs_err_t parse_return(struct pstate *p) { EXPECT(p, TOK_KEYWORD_RETURN); - parse_expr(p); + if (parse_expr(p) != MJS_OK) { + emit_byte(p, OP_PUSH_UNDEF); + } emit_byte(p, OP_SETRETVAL); emit_byte(p, OP_RETURN); return MJS_OK; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 5e0defa..969d433 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -245,6 +245,15 @@ const char *test_function(struct mjs *mjs) { CHECK_NUMERIC("function f(){}; f ? 1 : 2", 1); CHECK_NUMERIC("function f(x){return x ? {x:x} : 0}; f(f).x(0);", 0); + /* Test return without a value */ + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + function foo() { + return; + } + foo(); + ), &res)); + mjs_disown(mjs, &res); return NULL; } From 8c732ca61bc212321001acb903ee9dfd45585f4b Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 2 Dec 2017 20:55:09 +0200 Subject: [PATCH 117/265] Refuse to call non-callable value Closes https://github.com/cesanta/mjs/issues/30 PUBLISHED_FROM=3a5a34c674a0c1d596853d18ab6890331e6a6566 --- mjs.c | 8 +++++++- mjs/src/mjs_exec.c | 8 +++++++- mjs/tests/unit_test.c | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mjs.c b/mjs.c index d5dd51d..9316495 100644 --- a/mjs.c +++ b/mjs.c @@ -9599,7 +9599,13 @@ mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args) { mjs_val_t r, prev_this_val, retval_stack_idx; int i; - size_t addr = mjs_get_func_addr(func); + size_t addr; + + if (!mjs_is_function(func)) { + return mjs_set_errorf(mjs, MJS_TYPE_ERROR, "calling non-callable"); + } + + addr = mjs_get_func_addr(func); LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 99bd66f..0854914 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -1075,7 +1075,13 @@ mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func, mjs_val_t this_val, int nargs, mjs_val_t *args) { mjs_val_t r, prev_this_val, retval_stack_idx; int i; - size_t addr = mjs_get_func_addr(func); + size_t addr; + + if (!mjs_is_function(func)) { + return mjs_set_errorf(mjs, MJS_TYPE_ERROR, "calling non-callable"); + } + + addr = mjs_get_func_addr(func); LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func))); diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 969d433..3e3951a 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2993,6 +2993,10 @@ const char *test_call_api(struct mjs *mjs) { ASSERT_EQ(mjs_call(mjs, &res, func, obj, 0), MJS_OK); ASSERT_EQ(mjs_get_int(mjs, res), 100); + /* test calling non-callable */ + ASSERT_EQ(mjs_call(mjs, &res, MJS_UNDEFINED, MJS_UNDEFINED, 0), MJS_TYPE_ERROR); + ASSERT_EQ(mjs_apply(mjs, &res, MJS_UNDEFINED, MJS_UNDEFINED, 0, NULL), MJS_TYPE_ERROR); + mjs_disown(mjs, &obj); mjs_disown(mjs, &res); mjs_disown(mjs, &func); From 7296e35a82c5484f20a418095c5af1ae8289ada8 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 2 Dec 2017 11:26:58 +0000 Subject: [PATCH 118/265] Use 8k iobuf limit for aws PUBLISHED_FROM=971951e1eeb82078b986cd6e25e52cfc1ccef286 --- common/platforms/lwip/mg_lwip_ssl_if.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_ssl_if.c b/common/platforms/lwip/mg_lwip_ssl_if.c index ef03d54..04ed778 100644 --- a/common/platforms/lwip/mg_lwip_ssl_if.c +++ b/common/platforms/lwip/mg_lwip_ssl_if.c @@ -15,14 +15,6 @@ #define MG_LWIP_SSL_IO_SIZE 1024 #endif -/* - * Stop processing incoming SSL traffic when recv_mbuf.size is this big. - * It'a a uick solution for SSL recv pushback. - */ -#ifndef MG_LWIP_SSL_RECV_MBUF_LIMIT -#define MG_LWIP_SSL_RECV_MBUF_LIMIT 3072 -#endif - #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -103,7 +95,7 @@ void mg_lwip_ssl_recv(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; /* Don't deliver data before connect callback */ if (nc->flags & MG_F_CONNECTING) return; - while (nc->recv_mbuf.len < MG_LWIP_SSL_RECV_MBUF_LIMIT) { + while (nc->recv_mbuf.len < nc->recv_mbuf_limit) { char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE); if (buf == NULL) return; int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE); From 7a030c1e5564fcc731d01cab2970691068e3c7bf Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 3 Dec 2017 20:53:15 +0200 Subject: [PATCH 119/265] Improve docs PUBLISHED_FROM=3b75fd8247ba9028e0ef0c3e211e7c1a80013951 --- common/cs_file.h | 4 ++++ common/mg_str.h | 16 +++++++++++++++- mjs.c | 20 +++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/common/cs_file.h b/common/cs_file.h index d62fa8d..285f1c4 100644 --- a/common/cs_file.h +++ b/common/cs_file.h @@ -22,6 +22,10 @@ extern "C" { char *cs_read_file(const char *path, size_t *size); #ifdef CS_MMAP +/* + * Only on platforms which support mmapping: mmap file `path` to the returned + * address. File size is written to `*size`. + */ char *cs_mmap_file(const char *path, size_t *size); #endif diff --git a/common/mg_str.h b/common/mg_str.h index 029fafc..f3ed105 100644 --- a/common/mg_str.h +++ b/common/mg_str.h @@ -21,10 +21,14 @@ struct mg_str { }; /* - * Helper functions for creating mg_str struct from plain C string. + * Helper function for creating mg_str struct from plain C string. * `NULL` is allowed and becomes `{NULL, 0}`. */ struct mg_str mg_mk_str(const char *s); + +/* + * Like `mg_mk_str`, but takes string length explicitly. + */ struct mg_str mg_mk_str_n(const char *s, size_t len); /* Macro for initializing mg_str. */ @@ -59,9 +63,19 @@ struct mg_str mg_strdup_nul(const struct mg_str s); */ const char *mg_strchr(const struct mg_str s, int c); +/* + * Compare two `mg_str`s; return value is the same as `strcmp`. + */ int mg_strcmp(const struct mg_str str1, const struct mg_str str2); + +/* + * Like `mg_strcmp`, but compares at most `n` characters. + */ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); +/* + * Finds the first occurrence of a substring `needle` in the `haystack`. + */ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); #ifdef __cplusplus diff --git a/mjs.c b/mjs.c index 9316495..acf6098 100644 --- a/mjs.c +++ b/mjs.c @@ -1710,10 +1710,14 @@ struct mg_str { }; /* - * Helper functions for creating mg_str struct from plain C string. + * Helper function for creating mg_str struct from plain C string. * `NULL` is allowed and becomes `{NULL, 0}`. */ struct mg_str mg_mk_str(const char *s); + +/* + * Like `mg_mk_str`, but takes string length explicitly. + */ struct mg_str mg_mk_str_n(const char *s, size_t len); /* Macro for initializing mg_str. */ @@ -1748,9 +1752,19 @@ struct mg_str mg_strdup_nul(const struct mg_str s); */ const char *mg_strchr(const struct mg_str s, int c); +/* + * Compare two `mg_str`s; return value is the same as `strcmp`. + */ int mg_strcmp(const struct mg_str str1, const struct mg_str str2); + +/* + * Like `mg_strcmp`, but compares at most `n` characters. + */ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); +/* + * Finds the first occurrence of a substring `needle` in the `haystack`. + */ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); #ifdef __cplusplus @@ -1942,6 +1956,10 @@ extern "C" { char *cs_read_file(const char *path, size_t *size); #ifdef CS_MMAP +/* + * Only on platforms which support mmapping: mmap file `path` to the returned + * address. File size is written to `*size`. + */ char *cs_mmap_file(const char *path, size_t *size); #endif From 7a5252cb1906a34e91a383655beff43f89460845 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 10 Dec 2017 21:34:53 +0200 Subject: [PATCH 120/265] Control parser stack consumption Resolves https://github.com/cesanta/mjs/issues/58 PUBLISHED_FROM=4553166a9a1cb0b46f04fbbec9e22ddb0c10ec6f --- mjs.c | 16 ++++++++++++++-- mjs/src/mjs_parser.c | 15 +++++++++++++-- mjs/src/mjs_tok.h | 1 + mjs/tests/unit_test.c | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/mjs.c b/mjs.c index acf6098..b1836f3 100644 --- a/mjs.c +++ b/mjs.c @@ -4247,6 +4247,7 @@ struct pstate { int start_bcode_idx; /* Index in mjs->bcode at which parsing was started */ int cur_idx; /* Index in mjs->bcode at which newly generated code is inserted */ + int depth; }; enum { @@ -12234,12 +12235,21 @@ static void emit_op(struct pstate *pstate, int tok) { emit_byte(pstate, (uint8_t) tok); } +#define BINOP_STACK_FRAME_SIZE 16 +#define STACK_LIMIT 8192 + // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. #define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ do { \ mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + p->depth++; \ + if (p->depth > (STACK_LIMIT / BINOP_STACK_FRAME_SIZE)) { \ + mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "parser stack overflow"); \ + res = MJS_SYNTAX_ERROR; \ + goto binop_clean; \ + } \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) goto binop_clean; \ if (prev_op != TOK_EOF) emit_op(p, prev_op); \ if (findtok(ops, p->tok.tok) != TOK_EOF) { \ int op = p->tok.tok; \ @@ -12257,13 +12267,15 @@ static void emit_op(struct pstate *pstate, int tok) { op = TOK_EOF; \ } \ pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ + if ((res = f2(p, op)) != MJS_OK) goto binop_clean; \ \ if (off_if != 0) { \ mjs_bcode_insert_offset(p, p->mjs, off_if, \ p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ } \ } \ + binop_clean: \ + p->depth--; \ return res; \ } while (0) diff --git a/mjs/src/mjs_parser.c b/mjs/src/mjs_parser.c index 7ab130a..8ca4c33 100644 --- a/mjs/src/mjs_parser.c +++ b/mjs/src/mjs_parser.c @@ -70,12 +70,21 @@ static void emit_op(struct pstate *pstate, int tok) { emit_byte(pstate, (uint8_t) tok); } +#define BINOP_STACK_FRAME_SIZE 16 +#define STACK_LIMIT 8192 + // Intentionally left as macro rather than a function, to let the // compiler to inline calls and mimimize runtime stack usage. #define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op) \ do { \ mjs_err_t res = MJS_OK; \ - if ((res = f1(p, TOK_EOF)) != MJS_OK) return res; \ + p->depth++; \ + if (p->depth > (STACK_LIMIT / BINOP_STACK_FRAME_SIZE)) { \ + mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "parser stack overflow"); \ + res = MJS_SYNTAX_ERROR; \ + goto binop_clean; \ + } \ + if ((res = f1(p, TOK_EOF)) != MJS_OK) goto binop_clean; \ if (prev_op != TOK_EOF) emit_op(p, prev_op); \ if (findtok(ops, p->tok.tok) != TOK_EOF) { \ int op = p->tok.tok; \ @@ -93,13 +102,15 @@ static void emit_op(struct pstate *pstate, int tok) { op = TOK_EOF; \ } \ pnext1(p); \ - if ((res = f2(p, op)) != MJS_OK) return res; \ + if ((res = f2(p, op)) != MJS_OK) goto binop_clean; \ \ if (off_if != 0) { \ mjs_bcode_insert_offset(p, p->mjs, off_if, \ p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE); \ } \ } \ + binop_clean: \ + p->depth--; \ return res; \ } while (0) diff --git a/mjs/src/mjs_tok.h b/mjs/src/mjs_tok.h index c781976..5891164 100644 --- a/mjs/src/mjs_tok.h +++ b/mjs/src/mjs_tok.h @@ -31,6 +31,7 @@ struct pstate { int start_bcode_idx; /* Index in mjs->bcode at which parsing was started */ int cur_idx; /* Index in mjs->bcode at which newly generated code is inserted */ + int depth; }; enum { diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 3e3951a..e183fee 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -3657,6 +3657,20 @@ const char *test_parser(struct mjs *mjs) { CHECK_NUMERIC("let f = function(x){return x;}; f(1),f(2),f(3)", 3); ASSERT_EXEC_OK(mjs_exec(mjs, ";", &res)); ASSERT_EQ(res, MJS_UNDEFINED); + + /* 51 []s is ok */ + ASSERT_EQ(mjs_exec(mjs, + "let a = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];" + "let b = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];" + , &res), MJS_OK); + + /* 52 []s is not ok */ + ASSERT_EQ(mjs_exec(mjs, + "let a = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];" + "let b = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];" + , &res), MJS_SYNTAX_ERROR); + ASSERT_STREQ(mjs->error_msg, "parser stack overflow"); + mjs_disown(mjs, &res); return NULL; } From feedc46c867403b4f2e4adf4faf41f4d2bc6adfe Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 14 Dec 2017 19:26:30 +0200 Subject: [PATCH 121/265] Add inet_ntop and inet_pton to esp8266 PUBLISHED_FROM=0a321ace3753a518e299b795fb7a4eed19708bb6 --- common/platforms/platform_esp8266.h | 6 ++++++ mjs.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/common/platforms/platform_esp8266.h b/common/platforms/platform_esp8266.h index 5ceb26d..b397101 100644 --- a/common/platforms/platform_esp8266.h +++ b/common/platforms/platform_esp8266.h @@ -52,5 +52,11 @@ typedef struct stat cs_stat_t; #define CS_ENABLE_STDIO 1 #endif +#define inet_ntop(af, src, dst, size) \ + (((af) == AF_INET) ? ipaddr_ntoa_r((const ip_addr_t *) (src), (dst), (size)) \ + : NULL) +#define inet_pton(af, src, dst) \ + (((af) == AF_INET) ? ipaddr_aton((src), (ip_addr_t *) (dst)) : 0) + #endif /* CS_PLATFORM == CS_P_ESP8266 */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */ diff --git a/mjs.c b/mjs.c index b1836f3..51befcf 100644 --- a/mjs.c +++ b/mjs.c @@ -559,6 +559,12 @@ typedef struct stat cs_stat_t; #define CS_ENABLE_STDIO 1 #endif +#define inet_ntop(af, src, dst, size) \ + (((af) == AF_INET) ? ipaddr_ntoa_r((const ip_addr_t *) (src), (dst), (size)) \ + : NULL) +#define inet_pton(af, src, dst) \ + (((af) == AF_INET) ? ipaddr_aton((src), (ip_addr_t *) (dst)) : 0) + #endif /* CS_PLATFORM == CS_P_ESP8266 */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */ #ifdef MJS_MODULE_LINES From 5cfe890cb19853fcf351360dbb5b2e8e697419ee Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 15 Dec 2017 20:48:19 +0200 Subject: [PATCH 122/265] Rename fstr to mkstr, and add "copy" arg PUBLISHED_FROM=a043b2614f91639ffb258226446816fd3f719967 --- README.md | 11 ++++++++--- mjs.c | 23 ++++++++++++++++------- mjs/src/mjs_builtin.c | 2 +- mjs/src/mjs_string.c | 19 ++++++++++++++----- mjs/src/mjs_string.h | 2 +- mjs/tests/unit_test.c | 4 ++-- 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 90d5276..5ea758d 100644 --- a/README.md +++ b/README.md @@ -77,10 +77,15 @@ where it enables scripting for IoT devices. adding new elements. Example: let a = [1,2,3,4,5]; a.splice(1, 2, 100, 101, 102); a === [1,100,101,102,4,5]; -
let s = fstr(ptrVar, offset, length);
+
let s = mkstr(ptrVar, length);
Create a string backed by a C memory chunk. A string s starts - at memory location ptrVar + offset, and is length bytes long. - Short form is also available: fstr(ptrVar, length).
+ at memory location ptrVar, and is length bytes long. + +
let s = mkstr(ptrVar, offset, length, copy = false);
+
Like `mkstr(ptrVar, length)`, but string s starts + at memory location ptrVar + offset, and the caller can specify + whether the string needs to be copied to the internal mjs buffer. By default + it's not copied.
let f = ffi('int foo(int)');
Import C function into mJS. See next section.
diff --git a/mjs.c b/mjs.c index 51befcf..3945a22 100644 --- a/mjs.c +++ b/mjs.c @@ -3557,7 +3557,7 @@ MJS_PRIVATE mjs_val_t s_concat(struct mjs *mjs, mjs_val_t a, mjs_val_t b); MJS_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p, size_t len, uint8_t /*enum embstr_flags*/ flags); -MJS_PRIVATE void mjs_fstr(struct mjs *mjs); +MJS_PRIVATE void mjs_mkstr(struct mjs *mjs); MJS_PRIVATE void mjs_string_slice(struct mjs *mjs); MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs); @@ -7956,7 +7956,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "print", ~0, mjs_mk_foreign(mjs, mjs_print)); mjs_set(mjs, obj, "ffi", ~0, mjs_mk_foreign(mjs, mjs_ffi_call)); mjs_set(mjs, obj, "ffi_cb_free", ~0, mjs_mk_foreign(mjs, mjs_ffi_cb_free)); - mjs_set(mjs, obj, "fstr", ~0, mjs_mk_foreign(mjs, mjs_fstr)); + mjs_set(mjs, obj, "mkstr", ~0, mjs_mk_foreign(mjs, mjs_mkstr)); mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); @@ -13652,17 +13652,19 @@ MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs) { mjs_return(mjs, ret); } -MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { +MJS_PRIVATE void mjs_mkstr(struct mjs *mjs) { int nargs = mjs_nargs(mjs); mjs_val_t ret = MJS_UNDEFINED; char *ptr = NULL; int offset = 0; int len = 0; + int copy = 0; mjs_val_t ptr_v = MJS_UNDEFINED; mjs_val_t offset_v = MJS_UNDEFINED; mjs_val_t len_v = MJS_UNDEFINED; + mjs_val_t copy_v = MJS_UNDEFINED; if (nargs == 2) { ptr_v = mjs_arg(mjs, 0); @@ -13671,10 +13673,15 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { ptr_v = mjs_arg(mjs, 0); offset_v = mjs_arg(mjs, 1); len_v = mjs_arg(mjs, 2); + } else if (nargs == 4) { + ptr_v = mjs_arg(mjs, 0); + offset_v = mjs_arg(mjs, 1); + len_v = mjs_arg(mjs, 2); + copy_v = mjs_arg(mjs, 3); } else { - mjs_prepend_errorf( - mjs, MJS_TYPE_ERROR, - "fstr takes 2 or 3 arguments: (ptr, len) or (ptr, offset, len)"); + mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, + "mkstr takes 2, 3 or 4 arguments: (ptr, len), (ptr, " + "offset, len) or (ptr, offset, len, copy)"); goto clean; } @@ -13693,6 +13700,8 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { goto clean; } + copy = mjs_is_truthy(mjs, copy_v); + /* all arguments are fine */ ptr = (char *) mjs_get_ptr(mjs, ptr_v); @@ -13701,7 +13710,7 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { } len = mjs_get_int(mjs, len_v); - ret = mjs_mk_string(mjs, ptr + offset, len, 0 /* don't copy */); + ret = mjs_mk_string(mjs, ptr + offset, len, copy); clean: mjs_return(mjs, ret); diff --git a/mjs/src/mjs_builtin.c b/mjs/src/mjs_builtin.c index a5870bf..eef27b9 100644 --- a/mjs/src/mjs_builtin.c +++ b/mjs/src/mjs_builtin.c @@ -131,7 +131,7 @@ void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) { mjs_set(mjs, obj, "print", ~0, mjs_mk_foreign(mjs, mjs_print)); mjs_set(mjs, obj, "ffi", ~0, mjs_mk_foreign(mjs, mjs_ffi_call)); mjs_set(mjs, obj, "ffi_cb_free", ~0, mjs_mk_foreign(mjs, mjs_ffi_cb_free)); - mjs_set(mjs, obj, "fstr", ~0, mjs_mk_foreign(mjs, mjs_fstr)); + mjs_set(mjs, obj, "mkstr", ~0, mjs_mk_foreign(mjs, mjs_mkstr)); mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign(mjs, mjs_get_mjs)); mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign(mjs, mjs_die)); mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign(mjs, mjs_do_gc)); diff --git a/mjs/src/mjs_string.c b/mjs/src/mjs_string.c index 9ff4987..07495e4 100644 --- a/mjs/src/mjs_string.c +++ b/mjs/src/mjs_string.c @@ -333,17 +333,19 @@ MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs) { mjs_return(mjs, ret); } -MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { +MJS_PRIVATE void mjs_mkstr(struct mjs *mjs) { int nargs = mjs_nargs(mjs); mjs_val_t ret = MJS_UNDEFINED; char *ptr = NULL; int offset = 0; int len = 0; + int copy = 0; mjs_val_t ptr_v = MJS_UNDEFINED; mjs_val_t offset_v = MJS_UNDEFINED; mjs_val_t len_v = MJS_UNDEFINED; + mjs_val_t copy_v = MJS_UNDEFINED; if (nargs == 2) { ptr_v = mjs_arg(mjs, 0); @@ -352,10 +354,15 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { ptr_v = mjs_arg(mjs, 0); offset_v = mjs_arg(mjs, 1); len_v = mjs_arg(mjs, 2); + } else if (nargs == 4) { + ptr_v = mjs_arg(mjs, 0); + offset_v = mjs_arg(mjs, 1); + len_v = mjs_arg(mjs, 2); + copy_v = mjs_arg(mjs, 3); } else { - mjs_prepend_errorf( - mjs, MJS_TYPE_ERROR, - "fstr takes 2 or 3 arguments: (ptr, len) or (ptr, offset, len)"); + mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, + "mkstr takes 2, 3 or 4 arguments: (ptr, len), (ptr, " + "offset, len) or (ptr, offset, len, copy)"); goto clean; } @@ -374,6 +381,8 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { goto clean; } + copy = mjs_is_truthy(mjs, copy_v); + /* all arguments are fine */ ptr = (char *) mjs_get_ptr(mjs, ptr_v); @@ -382,7 +391,7 @@ MJS_PRIVATE void mjs_fstr(struct mjs *mjs) { } len = mjs_get_int(mjs, len_v); - ret = mjs_mk_string(mjs, ptr + offset, len, 0 /* don't copy */); + ret = mjs_mk_string(mjs, ptr + offset, len, copy); clean: mjs_return(mjs, ret); diff --git a/mjs/src/mjs_string.h b/mjs/src/mjs_string.h index 6a36a59..b86ced1 100644 --- a/mjs/src/mjs_string.h +++ b/mjs/src/mjs_string.h @@ -28,7 +28,7 @@ MJS_PRIVATE mjs_val_t s_concat(struct mjs *mjs, mjs_val_t a, mjs_val_t b); MJS_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p, size_t len, uint8_t /*enum embstr_flags*/ flags); -MJS_PRIVATE void mjs_fstr(struct mjs *mjs); +MJS_PRIVATE void mjs_mkstr(struct mjs *mjs); MJS_PRIVATE void mjs_string_slice(struct mjs *mjs); MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs); diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index e183fee..0b69394 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -3051,7 +3051,7 @@ const char *test_foreign_str(struct mjs *mjs) { STRINGIFY( let calloc = ffi('void *calloc(int, int)'); let ptr = calloc(100, 1); - let str = fstr(ptr, 3); + let str = mkstr(ptr, 3); ptr ), &res)); ptr = (unsigned char *)mjs_get_ptr(mjs, res); @@ -3071,7 +3071,7 @@ const char *test_foreign_str(struct mjs *mjs) { ASSERT_EXEC_OK(mjs_exec(mjs, "str === 'a\\x00b'", &res)); ASSERT_EQ(mjs_get_bool(mjs, res), 1); - ASSERT_EXEC_OK(mjs_exec(mjs, "let str2 = fstr(ptr, 2, 10); str2", &res)); + ASSERT_EXEC_OK(mjs_exec(mjs, "let str2 = mkstr(ptr, 2, 10); str2", &res)); ASSERT_EXEC_OK(mjs_exec(mjs, "str2 === 'b\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", &res)); ASSERT_EQ(mjs_get_bool(mjs, res), 1); From 6eed09d6ab9d56e80f87a8bf67cb54a6bf1386f9 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sat, 16 Dec 2017 18:21:51 +0200 Subject: [PATCH 123/265] Improve docs for logging PUBLISHED_FROM=72f0892ecfba5b1c3c2a70f0ecd5715578d7ffce --- common/cs_dbg.c | 10 +++---- common/cs_dbg.h | 70 +++++++++++++++++++++++++++++++++++++++++-- mjs.c | 80 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 144 insertions(+), 16 deletions(-) diff --git a/common/cs_dbg.c b/common/cs_dbg.c index 3128d41..1f08b9a 100644 --- a/common/cs_dbg.c +++ b/common/cs_dbg.c @@ -32,12 +32,12 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_set_filter(const char *str) WEAK; -void cs_log_set_filter(const char *str) { +void cs_log_set_filter(const char *pattern) WEAK; +void cs_log_set_filter(const char *pattern) { free(s_filter_pattern); - if (str != NULL) { - s_filter_pattern = strdup(str); - s_filter_pattern_len = strlen(str); + if (pattern != NULL) { + s_filter_pattern = strdup(pattern); + s_filter_pattern_len = strlen(pattern); } else { s_filter_pattern = NULL; s_filter_pattern_len = 0; diff --git a/common/cs_dbg.h b/common/cs_dbg.h index 0adbf45..24a7022 100644 --- a/common/cs_dbg.h +++ b/common/cs_dbg.h @@ -24,6 +24,9 @@ extern "C" { #endif /* __cplusplus */ +/* + * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it. + */ enum cs_log_level { LL_NONE = -1, LL_ERROR = 0, @@ -36,12 +39,54 @@ enum cs_log_level { _LL_MAX = 5, }; -/* Set log level. */ +/* + * Set max log level to print; messages with the level above the given one will + * not be printed. + */ void cs_log_set_level(enum cs_log_level level); -/* Set log filter. NULL (a default) logs everything. */ -void cs_log_set_filter(const char *source_file_name); +/* + * Set log filter. NULL (a default) logs everything. + * Otherwise, function name and file name will be tested against the given + * pattern, and only matching messages will be printed. + * + * For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`. + * + * Example: + * ```c + * void foo(void) { + * LOG(LL_INFO, ("hello from foo")); + * } + * + * void bar(void) { + * LOG(LL_INFO, ("hello from bar")); + * } + * + * void test(void) { + * cs_log_set_filter(NULL); + * foo(); + * bar(); + * + * cs_log_set_filter("f*"); + * foo(); + * bar(); // Will NOT print anything + * + * cs_log_set_filter("bar"); + * foo(); // Will NOT print anything + * bar(); + * } + * ``` + */ +void cs_log_set_filter(const char *pattern); +/* + * Helper function which prints message prefix with the given `level`, function + * name `func` and `filename`. If message should be printed (accordingly to the + * current log level and filter), prints the prefix and returns 1, otherwise + * returns 0. + * + * Clients should typically just use `LOG()` macro. + */ int cs_log_print_prefix(enum cs_log_level level, const char *func, const char *filename); @@ -49,13 +94,29 @@ extern enum cs_log_level cs_log_threshold; #if CS_ENABLE_STDIO +/* + * Set file to write logs into. If `NULL`, logs go to `stderr`. + */ void cs_log_set_file(FILE *file); + +/* + * Prints log to the current log file, appends "\n" in the end and flushes the + * stream. + */ void cs_log_printf(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; +/* + * Format and print message `x` with the given level `l`. Example: + * + * ```c + * LOG(LL_INFO, ("my info message: %d", 123)); + * LOG(LL_DEBUG, ("my debug message: %d", 123)); + * ``` + */ #define LOG(l, x) \ do { \ if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ @@ -63,6 +124,9 @@ void cs_log_printf(const char *fmt, ...) #ifndef CS_NDEBUG +/* + * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))` + */ #define DBG(x) LOG(LL_VERBOSE_DEBUG, x) #else /* NDEBUG */ diff --git a/mjs.c b/mjs.c index 3945a22..17770b2 100644 --- a/mjs.c +++ b/mjs.c @@ -1598,6 +1598,9 @@ typedef struct stat cs_stat_t; extern "C" { #endif /* __cplusplus */ +/* + * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it. + */ enum cs_log_level { LL_NONE = -1, LL_ERROR = 0, @@ -1610,12 +1613,54 @@ enum cs_log_level { _LL_MAX = 5, }; -/* Set log level. */ +/* + * Set max log level to print; messages with the level above the given one will + * not be printed. + */ void cs_log_set_level(enum cs_log_level level); -/* Set log filter. NULL (a default) logs everything. */ -void cs_log_set_filter(const char *source_file_name); +/* + * Set log filter. NULL (a default) logs everything. + * Otherwise, function name and file name will be tested against the given + * pattern, and only matching messages will be printed. + * + * For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`. + * + * Example: + * ```c + * void foo(void) { + * LOG(LL_INFO, ("hello from foo")); + * } + * + * void bar(void) { + * LOG(LL_INFO, ("hello from bar")); + * } + * + * void test(void) { + * cs_log_set_filter(NULL); + * foo(); + * bar(); + * + * cs_log_set_filter("f*"); + * foo(); + * bar(); // Will NOT print anything + * + * cs_log_set_filter("bar"); + * foo(); // Will NOT print anything + * bar(); + * } + * ``` + */ +void cs_log_set_filter(const char *pattern); +/* + * Helper function which prints message prefix with the given `level`, function + * name `func` and `filename`. If message should be printed (accordingly to the + * current log level and filter), prints the prefix and returns 1, otherwise + * returns 0. + * + * Clients should typically just use `LOG()` macro. + */ int cs_log_print_prefix(enum cs_log_level level, const char *func, const char *filename); @@ -1623,13 +1668,29 @@ extern enum cs_log_level cs_log_threshold; #if CS_ENABLE_STDIO +/* + * Set file to write logs into. If `NULL`, logs go to `stderr`. + */ void cs_log_set_file(FILE *file); + +/* + * Prints log to the current log file, appends "\n" in the end and flushes the + * stream. + */ void cs_log_printf(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; +/* + * Format and print message `x` with the given level `l`. Example: + * + * ```c + * LOG(LL_INFO, ("my info message: %d", 123)); + * LOG(LL_DEBUG, ("my debug message: %d", 123)); + * ``` + */ #define LOG(l, x) \ do { \ if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ @@ -1637,6 +1698,9 @@ void cs_log_printf(const char *fmt, ...) #ifndef CS_NDEBUG +/* + * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))` + */ #define DBG(x) LOG(LL_VERBOSE_DEBUG, x) #else /* NDEBUG */ @@ -4579,12 +4643,12 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_set_filter(const char *str) WEAK; -void cs_log_set_filter(const char *str) { +void cs_log_set_filter(const char *pattern) WEAK; +void cs_log_set_filter(const char *pattern) { free(s_filter_pattern); - if (str != NULL) { - s_filter_pattern = strdup(str); - s_filter_pattern_len = strlen(str); + if (pattern != NULL) { + s_filter_pattern = strdup(pattern); + s_filter_pattern_len = strlen(pattern); } else { s_filter_pattern = NULL; s_filter_pattern_len = 0; From da97e02b75b4220dc54a36bba234d16f87b01db4 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 17 Dec 2017 00:36:01 +0200 Subject: [PATCH 124/265] Slightly improve frozen doc PUBLISHED_FROM=191600deaa98dc00e05a642a3b8592a41c3e6a66 --- frozen/frozen.h | 2 +- mjs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frozen/frozen.h b/frozen/frozen.h index 7cbfb04..f66e04d 100644 --- a/frozen/frozen.h +++ b/frozen/frozen.h @@ -180,7 +180,7 @@ int json_printf_array(struct json_out *, va_list *ap); * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" * 2. Order of keys in an object is irrelevant. * 3. Several extra format specifiers are supported: - * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), + * - %B: consumes `int *` (or `char *`, if `sizeof(bool) == sizeof(char)`), * expects boolean `true` or `false`. * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned * string is malloc-ed, caller must free() the string. diff --git a/mjs.c b/mjs.c index 17770b2..4493f4b 100644 --- a/mjs.c +++ b/mjs.c @@ -3819,7 +3819,7 @@ int json_printf_array(struct json_out *, va_list *ap); * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}" * 2. Order of keys in an object is irrelevant. * 3. Several extra format specifiers are supported: - * - %B: consumes `int *` (or 'char *', if sizeof(bool) == sizeof(char)), + * - %B: consumes `int *` (or `char *`, if `sizeof(bool) == sizeof(char)`), * expects boolean `true` or `false`. * - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned * string is malloc-ed, caller must free() the string. From 32cdb6801b36942caf5ac100dfa1a510473de86e Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 17 Dec 2017 00:45:48 +0200 Subject: [PATCH 125/265] Improve docs of str_util.h PUBLISHED_FROM=de02f5cc6a9d854e92cf674e5382f793709da831 --- common/str_util.h | 25 +++++++++++++++++++++++++ mjs.c | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/common/str_util.h b/common/str_util.h index dccd0d2..6f237d8 100644 --- a/common/str_util.h +++ b/common/str_util.h @@ -41,9 +41,21 @@ extern "C" { #endif +/* + * Equivalent of standard `strnlen()`. + */ size_t c_strnlen(const char *s, size_t maxlen); + +/* + * Equivalent of standard `snprintf()`. + */ int c_snprintf(char *buf, size_t buf_size, const char *format, ...); + +/* + * Equivalent of standard `vsnprintf()`. + */ int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap); + /* * Find the first occurrence of find in s, where the search is limited to the * first slen characters of s. @@ -64,6 +76,9 @@ void cs_to_hex(char *to, const unsigned char *p, size_t len); void cs_from_hex(char *to, const char *p, size_t len); #if CS_ENABLE_STRDUP +/* + * Equivalent of standard `strdup()`, defined if only `CS_ENABLE_STRDUP` is 1. + */ char *strdup(const char *src); #endif @@ -91,12 +106,14 @@ int mg_casecmp(const char *s1, const char *s2); * enough buffer on heap and returns allocated buffer. * This is a supposed use case: * + * ```c * char buf[5], *p = buf; * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); * use_p_somehow(p); * if (p != buf) { * free(p); * } + * ``` * * The purpose of this is to avoid malloc-ing if generated strings are small. */ @@ -120,6 +137,10 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); */ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val); + +/* + * Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`. + */ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, struct mg_str *eq_val); @@ -145,6 +166,10 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, * ``` */ int mg_match_prefix(const char *pattern, int pattern_len, const char *str); + +/* + * Like `mg_match_prefix()`, but takes `pattern` and `str` as `struct mg_str`. + */ int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); #ifdef __cplusplus diff --git a/mjs.c b/mjs.c index 4493f4b..2598eb7 100644 --- a/mjs.c +++ b/mjs.c @@ -1888,9 +1888,21 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); extern "C" { #endif +/* + * Equivalent of standard `strnlen()`. + */ size_t c_strnlen(const char *s, size_t maxlen); + +/* + * Equivalent of standard `snprintf()`. + */ int c_snprintf(char *buf, size_t buf_size, const char *format, ...); + +/* + * Equivalent of standard `vsnprintf()`. + */ int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap); + /* * Find the first occurrence of find in s, where the search is limited to the * first slen characters of s. @@ -1911,6 +1923,9 @@ void cs_to_hex(char *to, const unsigned char *p, size_t len); void cs_from_hex(char *to, const char *p, size_t len); #if CS_ENABLE_STRDUP +/* + * Equivalent of standard `strdup()`, defined if only `CS_ENABLE_STRDUP` is 1. + */ char *strdup(const char *src); #endif @@ -1938,12 +1953,14 @@ int mg_casecmp(const char *s1, const char *s2); * enough buffer on heap and returns allocated buffer. * This is a supposed use case: * + * ```c * char buf[5], *p = buf; * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); * use_p_somehow(p); * if (p != buf) { * free(p); * } + * ``` * * The purpose of this is to avoid malloc-ing if generated strings are small. */ @@ -1967,6 +1984,10 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); */ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val); + +/* + * Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`. + */ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, struct mg_str *eq_val); @@ -1992,6 +2013,10 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, * ``` */ int mg_match_prefix(const char *pattern, int pattern_len, const char *str); + +/* + * Like `mg_match_prefix()`, but takes `pattern` and `str` as `struct mg_str`. + */ int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); #ifdef __cplusplus From f20dbb6466060d1a1b97c5e2ee0b7e99c069c7ab Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Mon, 18 Dec 2017 13:06:01 +0200 Subject: [PATCH 126/265] Implement Array.prototype.push PUBLISHED_FROM=8b09ac487fdc0b4c748b7e1fc22aab7aee93c15f --- mjs.c | 33 +++++++++++++++++++++++++++++++++ mjs/src/mjs_array.c | 28 ++++++++++++++++++++++++++++ mjs/src/mjs_array.h | 2 ++ mjs/src/mjs_exec.c | 3 +++ mjs/tests/unit_test.c | 16 ++++++++++++++++ 5 files changed, 82 insertions(+) diff --git a/mjs.c b/mjs.c index 2598eb7..f8e32c8 100644 --- a/mjs.c +++ b/mjs.c @@ -2697,6 +2697,8 @@ mjs_array_get2(struct mjs *mjs, mjs_val_t arr, unsigned long index, int *has); MJS_PRIVATE void mjs_array_splice(struct mjs *mjs); +MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs); + #if defined(__cplusplus) } #endif /* __cplusplus */ @@ -7667,6 +7669,34 @@ mjs_err_t mjs_array_push(struct mjs *mjs, mjs_val_t arr, mjs_val_t v) { return mjs_array_set(mjs, arr, mjs_array_length(mjs, arr), v); } +MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs) { + mjs_err_t rcode = MJS_OK; + mjs_val_t ret = MJS_UNDEFINED; + int nargs = mjs_nargs(mjs); + int i; + + /* Make sure that `this` is an array */ + if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_OBJECT_ARRAY, NULL)) { + goto clean; + } + + /* Push all args */ + for (i = 0; i < nargs; i++) { + rcode = mjs_array_push(mjs, mjs->vals.this_obj, mjs_arg(mjs, i)); + if (rcode != MJS_OK) { + mjs_prepend_errorf(mjs, rcode, ""); + goto clean; + } + } + + /* Return the new array length */ + ret = mjs_mk_number(mjs, mjs_array_length(mjs, mjs->vals.this_obj)); + +clean: + mjs_return(mjs, ret); + return; +} + static void move_item(struct mjs *mjs, mjs_val_t arr, unsigned long from, unsigned long to) { mjs_val_t cur = mjs_array_get(mjs, arr, from); @@ -9087,6 +9117,9 @@ static int getprop_builtin_array(struct mjs *mjs, mjs_val_t val, if (strcmp(name, "splice") == 0) { *res = mjs_mk_foreign(mjs, mjs_array_splice); return 1; + } else if (strcmp(name, "push") == 0) { + *res = mjs_mk_foreign(mjs, mjs_array_push_internal); + return 1; } else if (strcmp(name, "length") == 0) { *res = mjs_mk_number(mjs, mjs_array_length(mjs, val)); return 1; diff --git a/mjs/src/mjs_array.c b/mjs/src/mjs_array.c index 841a3ad..2eadd89 100644 --- a/mjs/src/mjs_array.c +++ b/mjs/src/mjs_array.c @@ -115,6 +115,34 @@ mjs_err_t mjs_array_push(struct mjs *mjs, mjs_val_t arr, mjs_val_t v) { return mjs_array_set(mjs, arr, mjs_array_length(mjs, arr), v); } +MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs) { + mjs_err_t rcode = MJS_OK; + mjs_val_t ret = MJS_UNDEFINED; + int nargs = mjs_nargs(mjs); + int i; + + /* Make sure that `this` is an array */ + if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_OBJECT_ARRAY, NULL)) { + goto clean; + } + + /* Push all args */ + for (i = 0; i < nargs; i++) { + rcode = mjs_array_push(mjs, mjs->vals.this_obj, mjs_arg(mjs, i)); + if (rcode != MJS_OK) { + mjs_prepend_errorf(mjs, rcode, ""); + goto clean; + } + } + + /* Return the new array length */ + ret = mjs_mk_number(mjs, mjs_array_length(mjs, mjs->vals.this_obj)); + +clean: + mjs_return(mjs, ret); + return; +} + static void move_item(struct mjs *mjs, mjs_val_t arr, unsigned long from, unsigned long to) { mjs_val_t cur = mjs_array_get(mjs, arr, from); diff --git a/mjs/src/mjs_array.h b/mjs/src/mjs_array.h index bae7a63..f2b1fe6 100644 --- a/mjs/src/mjs_array.h +++ b/mjs/src/mjs_array.h @@ -18,6 +18,8 @@ mjs_array_get2(struct mjs *mjs, mjs_val_t arr, unsigned long index, int *has); MJS_PRIVATE void mjs_array_splice(struct mjs *mjs); +MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs); + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/mjs/src/mjs_exec.c b/mjs/src/mjs_exec.c index 0854914..3cad779 100644 --- a/mjs/src/mjs_exec.c +++ b/mjs/src/mjs_exec.c @@ -449,6 +449,9 @@ static int getprop_builtin_array(struct mjs *mjs, mjs_val_t val, if (strcmp(name, "splice") == 0) { *res = mjs_mk_foreign(mjs, mjs_array_splice); return 1; + } else if (strcmp(name, "push") == 0) { + *res = mjs_mk_foreign(mjs, mjs_array_push_internal); + return 1; } else if (strcmp(name, "length") == 0) { *res = mjs_mk_number(mjs, mjs_array_length(mjs, val)); return 1; diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 0b69394..899b829 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2747,6 +2747,22 @@ const char *test_arrays(struct mjs *mjs) { ), &res)); ASSERT_STREQ(mjs_get_cstring(mjs, &res), "[]___[1,7,2,3]"); + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + let a=([1, 2, 3]); + let ret=a.push(10,20,30); + JSON.stringify(ret) + '___' + JSON.stringify(a) + ), &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), "6___[1,2,3,10,20,30]"); + + ASSERT_EXEC_OK(mjs_exec(mjs, + STRINGIFY( + let a=([]); + let ret=a.push(); + JSON.stringify(ret) + '___' + JSON.stringify(a) + ), &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), "0___[]"); + mjs_disown(mjs, &res); return NULL; From d5bbef37cb2d382cea040413ff4c273fa57e5ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sun, 17 Dec 2017 14:45:33 +0000 Subject: [PATCH 127/265] Implement helper mjs_struct_to_obj() PUBLISHED_FROM=2c3eed1b68847ecaa1a9ba115d7837d130119419 --- mjs.c | 99 +++++++++++++++++++++++++++++++------ mjs.h | 70 +++++++++++++++++++++++++- mjs/src/mjs_ffi.h | 13 ----- mjs/src/mjs_ffi_public.h | 15 ++++++ mjs/src/mjs_object.c | 54 +++++++++++++++++++- mjs/src/mjs_object_public.h | 14 +++++- mjs/src/mjs_string.c | 3 +- mjs/tests/unit_test.c | 39 +++++++++++++++ 8 files changed, 274 insertions(+), 33 deletions(-) diff --git a/mjs.c b/mjs.c index f8e32c8..1749b0b 100644 --- a/mjs.c +++ b/mjs.c @@ -2721,6 +2721,21 @@ MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs); extern "C" { #endif /* __cplusplus */ +enum mjs_ffi_ctype { + MJS_FFI_CTYPE_NONE, + MJS_FFI_CTYPE_USERDATA, + MJS_FFI_CTYPE_CALLBACK, + MJS_FFI_CTYPE_INT, + MJS_FFI_CTYPE_BOOL, + MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, + MJS_FFI_CTYPE_CHAR_PTR, + MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR, + MJS_FFI_CTYPE_INVALID, +}; + typedef void *(mjs_ffi_resolver_t)(void *handle, const char *symbol); void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); @@ -2754,19 +2769,6 @@ mjs_ffi_resolver_t dlsym; #define MJS_CB_ARGS_MAX_CNT 6 #define MJS_CB_SIGNATURE_MAX_SIZE (MJS_CB_ARGS_MAX_CNT + 1 /* return type */) -enum mjs_ffi_ctype { - MJS_FFI_CTYPE_NONE, - MJS_FFI_CTYPE_USERDATA, - MJS_FFI_CTYPE_CALLBACK, - MJS_FFI_CTYPE_INT, - MJS_FFI_CTYPE_BOOL, - MJS_FFI_CTYPE_DOUBLE, - MJS_FFI_CTYPE_FLOAT, - MJS_FFI_CTYPE_CHAR_PTR, - MJS_FFI_CTYPE_VOID_PTR, - MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, - MJS_FFI_CTYPE_INVALID, -}; typedef uint8_t mjs_ffi_ctype_t; enum ffi_sig_type { @@ -3237,8 +3239,9 @@ MJS_PRIVATE int mjs_is_truthy(struct mjs *mjs, mjs_val_t v); #ifndef MJS_OBJECT_PUBLIC_H_ #define MJS_OBJECT_PUBLIC_H_ -/* Amalgamated: #include "mjs/src/mjs_core_public.h" */ #include +/* Amalgamated: #include "mjs/src/mjs_core_public.h" */ +/* Amalgamated: #include "mjs/src/mjs_ffi_public.h" */ #if defined(__cplusplus) extern "C" { @@ -3252,6 +3255,17 @@ int mjs_is_object(mjs_val_t v); /* Make an empty object */ mjs_val_t mjs_mk_object(struct mjs *mjs); +/* C structure layout descriptor - needed by mjs_struct_to_obj */ +struct mjs_c_struct_member { + const char *name; + size_t offset; + enum mjs_ffi_ctype type; +}; + +/* Create flat JS object from a C memory descriptor */ +mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base, + const struct mjs_c_struct_member *members); + /* * Lookup property `name` in object `obj`. If `obj` holds no such property, * an `undefined` value is returned. @@ -12014,14 +12028,16 @@ int main(int argc, char *argv[]) { * All rights reserved */ +/* Amalgamated: #include "mjs/src/mjs_object.h" */ /* Amalgamated: #include "mjs/src/mjs_conversion.h" */ /* Amalgamated: #include "mjs/src/mjs_core.h" */ /* Amalgamated: #include "mjs/src/mjs_internal.h" */ -/* Amalgamated: #include "mjs/src/mjs_object.h" */ /* Amalgamated: #include "mjs/src/mjs_primitive.h" */ /* Amalgamated: #include "mjs/src/mjs_string.h" */ /* Amalgamated: #include "mjs/src/mjs_util.h" */ +/* Amalgamated: #include "common/mg_str.h" */ + MJS_PRIVATE mjs_val_t mjs_object_to_value(struct mjs_object *o) { if (o == NULL) { return MJS_NULL; @@ -12288,6 +12304,56 @@ MJS_PRIVATE void mjs_op_create_object(struct mjs *mjs) { clean: mjs_return(mjs, ret); } + +mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base, + const struct mjs_c_struct_member *def) { + mjs_val_t obj = mjs_mk_object(mjs); + for (; def->name != NULL; def++) { + const char *ptr = (const char *) base + def->offset; + switch (def->type) { + case MJS_FFI_CTYPE_INT: { + double value = (double) (*(int *) ptr); + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value)); + break; + } + case MJS_FFI_CTYPE_CHAR_PTR: { + const char *value = *(const char **) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, value, ~0, 1)); + break; + } + case MJS_FFI_CTYPE_DOUBLE: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, *(double *) ptr)); + break; + } + case MJS_FFI_CTYPE_STRUCT_MG_STR: { + const struct mg_str *s = (const struct mg_str *) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1)); + break; + } + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + const struct mg_str *s = *(const struct mg_str **) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1)); + break; + } + case MJS_FFI_CTYPE_FLOAT: { + float value = *(float *) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value)); + break; + } + case MJS_FFI_CTYPE_VOID_PTR: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_foreign(mjs, *(void **) ptr)); + break; + } + case MJS_FFI_CTYPE_BOOL: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_boolean(mjs, *(bool *) ptr)); + break; + } + default: + return MJS_UNDEFINED; + } + } + return obj; +} #ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_parser.c" #endif @@ -13444,11 +13510,12 @@ MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs) { * All rights reserved */ +/* Amalgamated: #include "mjs/src/mjs_string.h" */ /* Amalgamated: #include "common/cs_varint.h" */ +/* Amalgamated: #include "mjs/src/mjs_conversion.h" */ /* Amalgamated: #include "mjs/src/mjs_core.h" */ /* Amalgamated: #include "mjs/src/mjs_internal.h" */ /* Amalgamated: #include "mjs/src/mjs_primitive.h" */ -/* Amalgamated: #include "mjs/src/mjs_string.h" */ /* Amalgamated: #include "mjs/src/mjs_util.h" */ // No UTF diff --git a/mjs.h b/mjs.h index 430ee8f..be05510 100644 --- a/mjs.h +++ b/mjs.h @@ -290,6 +290,47 @@ void mjs_return(struct mjs *mjs, mjs_val_t v); #endif /* __cplusplus */ #endif /* MJS_CORE_PUBLIC_H_ */ +#ifdef MJS_MODULE_LINES +#line 1 "mjs/src/mjs_ffi_public.h" +#endif +/* + * Copyright (c) 2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef MJS_FFI_PUBLIC_H_ +#define MJS_FFI_PUBLIC_H_ + +/* Amalgamated: #include "mjs/src/mjs_core_public.h" */ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +enum mjs_ffi_ctype { + MJS_FFI_CTYPE_NONE, + MJS_FFI_CTYPE_USERDATA, + MJS_FFI_CTYPE_CALLBACK, + MJS_FFI_CTYPE_INT, + MJS_FFI_CTYPE_BOOL, + MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, + MJS_FFI_CTYPE_CHAR_PTR, + MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR, + MJS_FFI_CTYPE_INVALID, +}; + +typedef void *(mjs_ffi_resolver_t)(void *handle, const char *symbol); + +void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* MJS_FFI_PUBLIC_H_ */ #ifndef MJS_EXPORT_INTERNAL_HEADERS #ifdef MJS_MODULE_LINES #line 1 "mjs/src/mjs_array_public.h" @@ -628,6 +669,21 @@ mjs_val_t mjs_get_this(struct mjs *mjs); extern "C" { #endif /* __cplusplus */ +enum mjs_ffi_ctype { + MJS_FFI_CTYPE_NONE, + MJS_FFI_CTYPE_USERDATA, + MJS_FFI_CTYPE_CALLBACK, + MJS_FFI_CTYPE_INT, + MJS_FFI_CTYPE_BOOL, + MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, + MJS_FFI_CTYPE_CHAR_PTR, + MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR, + MJS_FFI_CTYPE_INVALID, +}; + typedef void *(mjs_ffi_resolver_t)(void *handle, const char *symbol); void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); @@ -648,8 +704,9 @@ void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); #ifndef MJS_OBJECT_PUBLIC_H_ #define MJS_OBJECT_PUBLIC_H_ -/* Amalgamated: #include "mjs/src/mjs_core_public.h" */ #include +/* Amalgamated: #include "mjs/src/mjs_core_public.h" */ +/* Amalgamated: #include "mjs/src/mjs_ffi_public.h" */ #if defined(__cplusplus) extern "C" { @@ -663,6 +720,17 @@ int mjs_is_object(mjs_val_t v); /* Make an empty object */ mjs_val_t mjs_mk_object(struct mjs *mjs); +/* C structure layout descriptor - needed by mjs_struct_to_obj */ +struct mjs_c_struct_member { + const char *name; + size_t offset; + enum mjs_ffi_ctype type; +}; + +/* Create flat JS object from a C memory descriptor */ +mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base, + const struct mjs_c_struct_member *members); + /* * Lookup property `name` in object `obj`. If `obj` holds no such property, * an `undefined` value is returned. diff --git a/mjs/src/mjs_ffi.h b/mjs/src/mjs_ffi.h index 3715211..dc30b87 100644 --- a/mjs/src/mjs_ffi.h +++ b/mjs/src/mjs_ffi.h @@ -19,19 +19,6 @@ mjs_ffi_resolver_t dlsym; #define MJS_CB_ARGS_MAX_CNT 6 #define MJS_CB_SIGNATURE_MAX_SIZE (MJS_CB_ARGS_MAX_CNT + 1 /* return type */) -enum mjs_ffi_ctype { - MJS_FFI_CTYPE_NONE, - MJS_FFI_CTYPE_USERDATA, - MJS_FFI_CTYPE_CALLBACK, - MJS_FFI_CTYPE_INT, - MJS_FFI_CTYPE_BOOL, - MJS_FFI_CTYPE_DOUBLE, - MJS_FFI_CTYPE_FLOAT, - MJS_FFI_CTYPE_CHAR_PTR, - MJS_FFI_CTYPE_VOID_PTR, - MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, - MJS_FFI_CTYPE_INVALID, -}; typedef uint8_t mjs_ffi_ctype_t; enum ffi_sig_type { diff --git a/mjs/src/mjs_ffi_public.h b/mjs/src/mjs_ffi_public.h index 65f8a1e..467cb86 100644 --- a/mjs/src/mjs_ffi_public.h +++ b/mjs/src/mjs_ffi_public.h @@ -12,6 +12,21 @@ extern "C" { #endif /* __cplusplus */ +enum mjs_ffi_ctype { + MJS_FFI_CTYPE_NONE, + MJS_FFI_CTYPE_USERDATA, + MJS_FFI_CTYPE_CALLBACK, + MJS_FFI_CTYPE_INT, + MJS_FFI_CTYPE_BOOL, + MJS_FFI_CTYPE_DOUBLE, + MJS_FFI_CTYPE_FLOAT, + MJS_FFI_CTYPE_CHAR_PTR, + MJS_FFI_CTYPE_VOID_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR_PTR, + MJS_FFI_CTYPE_STRUCT_MG_STR, + MJS_FFI_CTYPE_INVALID, +}; + typedef void *(mjs_ffi_resolver_t)(void *handle, const char *symbol); void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym); diff --git a/mjs/src/mjs_object.c b/mjs/src/mjs_object.c index 2de7796..7f5464d 100644 --- a/mjs/src/mjs_object.c +++ b/mjs/src/mjs_object.c @@ -3,14 +3,16 @@ * All rights reserved */ +#include "mjs/src/mjs_object.h" #include "mjs/src/mjs_conversion.h" #include "mjs/src/mjs_core.h" #include "mjs/src/mjs_internal.h" -#include "mjs/src/mjs_object.h" #include "mjs/src/mjs_primitive.h" #include "mjs/src/mjs_string.h" #include "mjs/src/mjs_util.h" +#include "common/mg_str.h" + MJS_PRIVATE mjs_val_t mjs_object_to_value(struct mjs_object *o) { if (o == NULL) { return MJS_NULL; @@ -277,3 +279,53 @@ MJS_PRIVATE void mjs_op_create_object(struct mjs *mjs) { clean: mjs_return(mjs, ret); } + +mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base, + const struct mjs_c_struct_member *def) { + mjs_val_t obj = mjs_mk_object(mjs); + for (; def->name != NULL; def++) { + const char *ptr = (const char *) base + def->offset; + switch (def->type) { + case MJS_FFI_CTYPE_INT: { + double value = (double) (*(int *) ptr); + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value)); + break; + } + case MJS_FFI_CTYPE_CHAR_PTR: { + const char *value = *(const char **) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, value, ~0, 1)); + break; + } + case MJS_FFI_CTYPE_DOUBLE: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, *(double *) ptr)); + break; + } + case MJS_FFI_CTYPE_STRUCT_MG_STR: { + const struct mg_str *s = (const struct mg_str *) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1)); + break; + } + case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: { + const struct mg_str *s = *(const struct mg_str **) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1)); + break; + } + case MJS_FFI_CTYPE_FLOAT: { + float value = *(float *) ptr; + mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value)); + break; + } + case MJS_FFI_CTYPE_VOID_PTR: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_foreign(mjs, *(void **) ptr)); + break; + } + case MJS_FFI_CTYPE_BOOL: { + mjs_set(mjs, obj, def->name, ~0, mjs_mk_boolean(mjs, *(bool *) ptr)); + break; + } + default: + return MJS_UNDEFINED; + } + } + return obj; +} diff --git a/mjs/src/mjs_object_public.h b/mjs/src/mjs_object_public.h index 269e2a6..77e2e35 100644 --- a/mjs/src/mjs_object_public.h +++ b/mjs/src/mjs_object_public.h @@ -6,8 +6,9 @@ #ifndef MJS_OBJECT_PUBLIC_H_ #define MJS_OBJECT_PUBLIC_H_ -#include "mjs/src/mjs_core_public.h" #include +#include "mjs/src/mjs_core_public.h" +#include "mjs/src/mjs_ffi_public.h" #if defined(__cplusplus) extern "C" { @@ -21,6 +22,17 @@ int mjs_is_object(mjs_val_t v); /* Make an empty object */ mjs_val_t mjs_mk_object(struct mjs *mjs); +/* C structure layout descriptor - needed by mjs_struct_to_obj */ +struct mjs_c_struct_member { + const char *name; + size_t offset; + enum mjs_ffi_ctype type; +}; + +/* Create flat JS object from a C memory descriptor */ +mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base, + const struct mjs_c_struct_member *members); + /* * Lookup property `name` in object `obj`. If `obj` holds no such property, * an `undefined` value is returned. diff --git a/mjs/src/mjs_string.c b/mjs/src/mjs_string.c index 07495e4..524512f 100644 --- a/mjs/src/mjs_string.c +++ b/mjs/src/mjs_string.c @@ -3,11 +3,12 @@ * All rights reserved */ +#include "mjs/src/mjs_string.h" #include "common/cs_varint.h" +#include "mjs/src/mjs_conversion.h" #include "mjs/src/mjs_core.h" #include "mjs/src/mjs_internal.h" #include "mjs/src/mjs_primitive.h" -#include "mjs/src/mjs_string.h" #include "mjs/src/mjs_util.h" // No UTF diff --git a/mjs/tests/unit_test.c b/mjs/tests/unit_test.c index 899b829..82ed2c3 100644 --- a/mjs/tests/unit_test.c +++ b/mjs/tests/unit_test.c @@ -2623,6 +2623,45 @@ const char *test_objects(struct mjs *mjs) { "p_foo:3_o1_foo:2_o2_foo:3_" ); + { + struct mg_str dummy = mg_mk_str("baz"); + struct my { + int a; + const char *b; + double c; + struct mg_str d; + struct mg_str *e; + float f; + bool g; + } s = {17, "foo", 12.34, {"bar", 3}, &dummy, 45.67f, true}; + const struct mjs_c_struct_member def[] = { + {"a", offsetof(struct my, a), MJS_FFI_CTYPE_INT}, + {"b", offsetof(struct my, b), MJS_FFI_CTYPE_CHAR_PTR}, + {"c", offsetof(struct my, c), MJS_FFI_CTYPE_DOUBLE}, + {"d", offsetof(struct my, d), MJS_FFI_CTYPE_STRUCT_MG_STR}, + {"e", offsetof(struct my, e), MJS_FFI_CTYPE_STRUCT_MG_STR_PTR}, + {"f", offsetof(struct my, f), MJS_FFI_CTYPE_FLOAT}, + {"g", offsetof(struct my, g), MJS_FFI_CTYPE_BOOL}, + {NULL, 0, MJS_FFI_CTYPE_NONE}, + }; + mjs_val_t v = mjs_struct_to_obj(mjs, &s, def); + mjs_set(mjs, mjs_get_global(mjs), "my", ~0, v); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.a", &res)); + ASSERT_EQ(mjs_get_int(mjs, res), 17); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.b", &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), "foo"); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.c", &res)); + ASSERT_EQ(mjs_get_double(mjs, res), 12.34); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.d", &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), "bar"); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.e", &res)); + ASSERT_STREQ(mjs_get_cstring(mjs, &res), "baz"); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.f", &res)); + ASSERT_EQ(mjs_get_double(mjs, res), 45.67f); + ASSERT_EXEC_OK(mjs_exec(mjs, "my.g", &res)); + ASSERT_EQ(mjs_get_bool(mjs, res), true); + } + mjs_disown(mjs, &res); return NULL; From a19ad75bb8f5c46e10ad050a636d22224246cf6b Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 28 Dec 2017 12:06:08 +0200 Subject: [PATCH 128/265] Respect recv_mbuf_limit in lwip PUBLISHED_FROM=470ff0f484bff3e4478651f0b64cc160bba8ebfc --- common/platforms/lwip/mg_lwip_net_if.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 7c0b9bf..6ff3861 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -187,9 +187,12 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { #endif mgos_lock(); - while (cs->rx_chain != NULL) { + while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) { struct pbuf *seg = cs->rx_chain; - size_t len = (seg->len - cs->rx_offset); + size_t seg_len = (seg->len - cs->rx_offset); + size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len); + size_t len = MIN(seg_len, buf_avail); + char *data = (char *) MG_MALLOC(len); if (data == NULL) { mgos_unlock(); From 66bc608d69c48dbb55b47dd482407867f9efc1c0 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 29 Dec 2017 00:54:59 +0200 Subject: [PATCH 129/265] Drain rx_chain before closing the connection PUBLISHED_FROM=08eee4052dd9bbc364875a577409cb78665dee30 --- common/platforms/lwip/mg_lwip_ev_mgr.c | 15 +++++++++- common/platforms/lwip/mg_lwip_net_if.c | 41 +++++++++++++++++--------- common/platforms/lwip/mg_lwip_net_if.h | 4 ++- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/common/platforms/lwip/mg_lwip_ev_mgr.c b/common/platforms/lwip/mg_lwip_ev_mgr.c index 7c4c8bf..5eea26f 100644 --- a/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -62,7 +62,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { break; } case MG_SIG_CLOSE_CONN: { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; + nc->flags |= MG_F_SEND_AND_CLOSE; mg_close_conn(nc); break; } @@ -173,6 +173,19 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { } num_timers++; } + + if (nc->sock != INVALID_SOCKET) { + /* Try to consume data from cs->rx_chain */ + mg_lwip_consume_rx_chain_tcp(nc); + + /* + * If the connection is about to close, and rx_chain is finally empty, + * send the MG_SIG_CLOSE_CONN signal + */ + if (cs->draining_rx_chain && cs->rx_chain == NULL) { + mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); + } + } } #if 0 DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms", diff --git a/common/platforms/lwip/mg_lwip_net_if.c b/common/platforms/lwip/mg_lwip_net_if.c index 6ff3861..d7807d0 100644 --- a/common/platforms/lwip/mg_lwip_net_if.c +++ b/common/platforms/lwip/mg_lwip_net_if.c @@ -135,7 +135,16 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); if (p == NULL) { if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (cs->rx_chain != NULL) { + /* + * rx_chain still contains non-consumed data, don't close the + * connection + */ + cs->draining_rx_chain = 1; + } else { + mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); + } } else { /* Tombstoned connection, do nothing. */ } @@ -172,23 +181,12 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, return ERR_OK; } -static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { +static void mg_lwip_consume_rx_chain_tcp(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - -#if MG_ENABLE_SSL - if (nc->flags & MG_F_SSL) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - mg_lwip_ssl_recv(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - return; - } -#endif - mgos_lock(); while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) { struct pbuf *seg = cs->rx_chain; + size_t seg_len = (seg->len - cs->rx_offset); size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len); size_t len = MIN(seg_len, buf_avail); @@ -211,6 +209,21 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { mgos_lock(); } mgos_unlock(); +} + +static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { +#if MG_ENABLE_SSL + if (nc->flags & MG_F_SSL) { + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { + mg_lwip_ssl_recv(nc); + } else { + mg_lwip_ssl_do_hs(nc); + } + return; + } +#endif + + mg_lwip_consume_rx_chain_tcp(nc); if (nc->send_mbuf.len > 0) { mg_lwip_mgr_schedule_poll(nc->mgr); diff --git a/common/platforms/lwip/mg_lwip_net_if.h b/common/platforms/lwip/mg_lwip_net_if.h index c48d0d7..d00fd2f 100644 --- a/common/platforms/lwip/mg_lwip_net_if.h +++ b/common/platforms/lwip/mg_lwip_net_if.h @@ -30,7 +30,9 @@ struct mg_lwip_conn_state { /* Last SSL write size, for retries. */ int last_ssl_write_size; /* Whether MG_SIG_RECV is already pending for this connection */ - int recv_pending; + int recv_pending : 1; + /* Whether the connection is about to close, just `rx_chain` needs to drain */ + int draining_rx_chain : 1; }; enum mg_sig_type { From 5c045140aa6afafc7fff3563f2f92bcdc998fb31 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 4 Jan 2018 13:28:19 +0300 Subject: [PATCH 130/265] Use stock ARM GCC and Newlib from Ubuntu distro Standardize common packages in build images, to make better use of Docker image cache. PUBLISHED_FROM=a080e83cf5dd80feaf7960147dee36413244a92c --- common/platforms/platform_stm32.h | 12 ++++++------ mjs.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/platforms/platform_stm32.h b/common/platforms/platform_stm32.h index 8f6f9d9..8fbaa80 100644 --- a/common/platforms/platform_stm32.h +++ b/common/platforms/platform_stm32.h @@ -7,15 +7,15 @@ #define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ #if CS_PLATFORM == CS_P_STM32 -#include -#include -#include -#include -#include #include #include -#include #include +#include +#include +#include +#include +#include +#include #include #define to64(x) strtoll(x, NULL, 10) diff --git a/mjs.c b/mjs.c index 1749b0b..9f6aa52 100644 --- a/mjs.c +++ b/mjs.c @@ -1540,15 +1540,15 @@ char *inet_ntoa(struct in_addr in); #define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ #if CS_PLATFORM == CS_P_STM32 -#include -#include -#include -#include -#include #include #include -#include #include +#include +#include +#include +#include +#include +#include #include #define to64(x) strtoll(x, NULL, 10) From 1969081a408d50448f165cedb06f7286228d40ca Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 27 Nov 2017 19:33:39 +0300 Subject: [PATCH 131/265] STM32: Basic FreeRTOS support, exception handling Also unify core dumping and analysis between STM32 and ESP8266. ESP32 and CC32xx next. PUBLISHED_FROM=9afcbebc0a58a7dd3f68379b777acea890c824bc --- common/platforms/cc3200/cc3200.ld | 2 +- common/platforms/esp/debug_coredump.mk | 25 -- common/platforms/esp/serve_core.py | 339 ------------------------- 3 files changed, 1 insertion(+), 365 deletions(-) delete mode 100644 common/platforms/esp/debug_coredump.mk delete mode 100755 common/platforms/esp/serve_core.py diff --git a/common/platforms/cc3200/cc3200.ld b/common/platforms/cc3200/cc3200.ld index 112673b..a2df648 100644 --- a/common/platforms/cc3200/cc3200.ld +++ b/common/platforms/cc3200/cc3200.ld @@ -88,5 +88,5 @@ SECTIONS . = ALIGN(8); _eheap = .; - } + } > SRAM } diff --git a/common/platforms/esp/debug_coredump.mk b/common/platforms/esp/debug_coredump.mk deleted file mode 100644 index 6c095f0..0000000 --- a/common/platforms/esp/debug_coredump.mk +++ /dev/null @@ -1,25 +0,0 @@ -# This provides a debug_coredump target for ESP8266 and ESP32. - -OBJ_DIR ?= build/objs -BIN_FILE ?= $(OBJ_DIR)/$(APP).bin -ELF_FILE ?= $(OBJ_DIR)/fw.elf - -debug_coredump: -ifndef CONSOLE_LOG - $(error Please set CONSOLE_LOG) -endif - docker run --rm -i --tty=true \ - -v $(APP_MOUNT_PATH):$(DOCKER_APP_PATH) \ - -v $(MGOS_PATH_ABS):$(DOCKER_MGOS_PATH) \ - -v $(MGOS_PATH_ABS):$(MGOS_PATH_ABS) \ - -v $(realpath $(ELF_FILE)):/app.elf \ - -v $(realpath $(CONSOLE_LOG)):/console.log \ - $(SDK_VERSION) /bin/bash -c "\ - cd $(DOCKER_APP_PATH)/$(APP_SUBDIR); \ - $(DOCKER_MGOS_PATH)/common/platforms/esp/serve_core.py \ - --rom $(DOCKER_MGOS_PATH)/common/platforms/$(APP_PLATFORM)/rom/rom.bin \ - /app.elf /console.log & \ - $(GDB) /app.elf \ - -ex 'target remote 127.0.0.1:1234' \ - -ex 'set confirm off' \ - -ex 'add-symbol-file $(DOCKER_MGOS_PATH)/common/platforms/$(APP_PLATFORM)/rom/rom.elf 0x40000000'" diff --git a/common/platforms/esp/serve_core.py b/common/platforms/esp/serve_core.py deleted file mode 100755 index 2ff0d0e..0000000 --- a/common/platforms/esp/serve_core.py +++ /dev/null @@ -1,339 +0,0 @@ -#!/usr/bin/env python - -# -# usage: tools/serve_core.py build/fw/objs/fw.elf /tmp/console.log -# -# Then you can connect with gdb. The ESP8266 SDK image provides a debugger with -# reasonable support of lx106. Example invocation: -# -# docker run -v $PWD:/cesanta -ti \ -# docker.cesanta.com/esp8266-build-oss:latest \ -# xt-gdb /cesanta/fw/platforms/esp8266/build/fw.out \ -# -ex "target remote localhost:1234" -# -# If you run on OSX or windows, you have to put the IP of your host instead of -# localhost since gdb will run in a virtualmachine. - -import SocketServer -import argparse -import base64 -import binascii -import ctypes -import json -import os -import re -import struct -import sys - -import elftools.elf.elffile # apt install python-pyelftools - -ROM_BASE= 0x40000000 - -parser = argparse.ArgumentParser(description='Serve ESP core dump to GDB') -parser.add_argument('--port', dest='port', default=1234, type=int, help='listening port') -parser.add_argument('--rom', dest='rom', required=False, help='rom section') -parser.add_argument('--rom_addr', dest='rom_addr', default=ROM_BASE, - type=lambda x: int(x,16), help='rom section') -parser.add_argument('elf', help='Program executable') -parser.add_argument('log', help='serial log containing core dump snippet') - -args = parser.parse_args() - -START_DELIM = '--- BEGIN CORE DUMP ---' -END_DELIM = '---- END CORE DUMP ----' - - -configMAX_TASK_NAME_LEN = 16 -XT_SOL_FRMSZ = 32 -XT_STK_FRMSZ = 192 -XT_STK_EXTRA = 112 -XCHAL_EXTRA_SA_SIZE = 48 - -class FreeRTOSTask(object): - handle = 0 - pxTopOfStack = 0 - uxPriority = 0 - pxStack = 0 - pcTaskName = "" - - def __init__(self, handle, data): - self.handle = handle - self.pxTopOfStack = struct.unpack('= 0: - self.pcTaskName = self.pcTaskName[0:i] - - def __str__(self): - return "0x%08x '%s' pri %d sp 0x%08x (%d free)" % ( - self.handle, self.pcTaskName, self.uxPriority, self.pxTopOfStack, - self.pxTopOfStack - self.pxStack) - - -class Core(object): - def __init__(self, filename): - self._dump = self._read(filename) - self.mem = self._map_core(self._dump) - if args.rom_addr: - self.mem.extend(self._map_firmware(args.rom_addr, args.rom, ROM_BASE)) - self.mem.extend(self._map_elf(args.elf)) - self.regs = base64.decodestring(self._dump['REGS']['data']) - self.tasks = dict((a, self._parse_tcb(a)) for a in self._dump.get('tasks', [])) - - def get_cur_task_for_cpu(self, cpu_no): - tt = self._dump.get('tasks', []) - if cpu_no < len(tt): - return tt[cpu_no] - else: - return None - - def _parse_tcb(self, addr): - sizeofTCB = 352 # sizeof(taskTCB) - # Task ID is the address of the TCB and must be in DRAM. - tcb_data = self.read(addr, sizeofTCB) - if tcb_data[3] != '\x3f': - return None - return FreeRTOSTask(addr, tcb_data) - - - def _search_backwards(self, f, start_offset, pattern): - offset = start_offset - while True: - offset = max(0, offset - 10000) - f.seek(offset) - data = f.read(min(10000, start_offset)) - pos = data.rfind(pattern) - if pos >= 0: - return offset + pos - elif offset == 0: - return -1 - offset += 5000 - - def _read(self, filename): - with open(filename) as f: - f.seek(0, os.SEEK_END) - size = f.tell() - end_pos = self._search_backwards(f, f.tell(), END_DELIM) - if end_pos == -1: - print >>sys.stderr, "Cannot find end delimiter:", END_DELIM - sys.exit(1) - start_pos = self._search_backwards(f, end_pos, START_DELIM) - if start_pos == -1: - print >>sys.stderr, "Cannot find start delimiter:", START_DELIM - sys.exit(1) - start_pos += len(START_DELIM) - - print >>sys.stderr, "Found core at %d - %d" % (start_pos, end_pos) - f.seek(start_pos) - core_json = f.read(end_pos - start_pos) - stripped = re.sub(r'(?im)\s+(\[.{1,40}\])?\s*', '', core_json) - return json.loads(stripped) - - def _map_core(self, core): - mem = [] - for k, v in core.items(): - if not isinstance(v, dict) or k == 'REGS': - continue - data = base64.decodestring(v["data"]) - print >>sys.stderr, "Mapping {0}: {1} @ {2:#02x}".format(k, len(data), v["addr"]) - if "crc32" in v: - crc32 = ctypes.c_uint32(binascii.crc32(data)) - expected_crc32 = ctypes.c_uint32(v["crc32"]) - if crc32.value != expected_crc32.value: - print >>sys.stderr, "CRC mismatch, section corrupted %s %s" % (crc32, expected_crc32) - sys.exit(1) - mem.append((v["addr"], v["addr"] + len(data), data)) - return mem - - def _map_firmware(self, addr, filename, base): - if addr is None: - name = os.path.splitext(os.path.basename(filename))[0] - addr = base + int(name, 16) - with open(filename) as f: - data = f.read() - result = [] - i = 0 - magic, count = struct.unpack('>sys.stderr, "Mapping IROM: {0} @ {1:#02x}".format(irom_len, addr) - result.append((addr, addr + irom_len, data[i:i+irom_len+16])) - # The rest (IRAM) will be in the core. - else: - print >>sys.stderr, "Mapping {0} at {1:#02x}".format(filename, addr) - result.append((addr, addr + len(data), data)) - return result - - def _map_elf(self, elf_file_name): - result = [] - f = open(elf_file_name) - ef = elftools.elf.elffile.ELFFile(f) - for i, sec in enumerate(ef.iter_sections()): - addr, size, off = sec["sh_addr"], sec["sh_size"], sec["sh_offset"] - if addr > 0 and size > 0: - print >>sys.stderr, "Mapping {0}: {1} @ {2:#02x}".format(sec.name, size, addr) - f.seek(off) - assert f.tell() == off - data = f.read(size) - assert len(data) == size - result.append((addr, addr + size, data)) - return result - - def read(self, addr, size): - for base, end, data in self.mem: - if addr >= base and addr < end: - return data[addr - base : addr - base + size] - print >>sys.stderr, "Unmapped addr", hex(addr) - return "\0" * size - - -class GDBHandler(SocketServer.BaseRequestHandler): - def handle(self): - self._core = core = Core(args.log) - self._curtask = None - print >>sys.stderr, "Loaded core dump from last snippet in ", args.log - - while self.expect_packet_start(): - pkt = self.read_packet() - #print >>sys.stderr, ">>", pkt - if pkt == "?": # status -> trap - self.send_str("S09") - elif pkt == "g": # dump registers - regs = core.regs - if self._curtask: - # Dump specific task's registers - t = self._curtask - sp = t.pxTopOfStack - # The first word on the stack of a task determines how - # task's execution ended: by yield (0) or int/exc (non-0). - exit, pc, ps = struct.unpack('>sys.stderr, "task %x pc %x sp %x" % (self._curtask.handle, pc, sp) - self.send_str(self.encode_bytes(regs)) - elif pkt[0] == "G": # set registers - core.regs = self.decode_bytes(pkt[1:]) - self.send_str("OK") - elif pkt[0] == "m": # read memory - addr, size = [int(n, 16) for n in pkt[1:].split(',')] - if addr < 0x10000000 and addr > 0x80000: - print >>sys.stderr, 'fixup %08x' % addr - addr |= 0x40000000 - bs = core.read(addr, size) - #if bs == "\0\0\0\0": - # bs = "\x01\0\0\0" - #print >>sys.stderr, "<<", " ".join("{:02x}".format(ord(c)) for c in bs) - self.send_str(self.encode_bytes(bs)) - elif pkt.startswith("Hg"): - tid = int(pkt[2:], 16) - self._curtask = core.tasks.get(tid) - self.send_str("OK") - elif pkt.startswith("Hc-1"): - # cannot continue, this is post mortem debugging - self.send_str("E01") - elif pkt == "qC": - t = core.get_cur_task_for_cpu(0) - if t: - self.send_str("QC%016x" % t) - self.send_str("1") - elif pkt == "qAttached": - self.send_str("1") - elif pkt == "qSymbol::": - self.send_str("OK") - elif pkt == "qfThreadInfo": - if core.tasks: - self.send_str("m%s" % ",".join("%016x" % t for t in core.tasks)) - else: - self.send_str("l") - elif pkt == "qsThreadInfo": - self.send_str("l") - elif pkt.startswith("qThreadExtraInfo,"): - self.send_thread_extra_info(int(pkt[17:], 16)) - elif pkt[0] == "T": - tid = int(pkt[1:], 16) - if tid in core.tasks: - self.send_str("OK") - else: - self.send_str("ERR00") - elif pkt in ("qTStatus", "qOffsets", "D") or pkt.startswith("qSupported"): - # silently ignore - self.send_str("") - else: - print >>sys.stderr, "Ignoring unknown command '%s'" % (pkt,) - self.send_str("") - - print >>sys.stderr, "GDB closed the connection" - - def encode_bytes(self, bs): - return "".join("{0:02x}".format(ord(i)) for i in bs) - - def decode_bytes(self, s): - return s.decode('hex') - - def send_ack(self): - self.request.sendall("+"); - - def send_nack(self): - self.request.sendall("-"); - - def send_str(self, s): - self.request.sendall("${0}#{1:02x}".format(s, self._checksum(s))) - - def _checksum(self, s): - return sum(ord(i) for i in s) % 0x100 - - def expect_packet_start(self): - return len(self.read_until('$')) > 0 - - def read_packet(self): - pkt = self.read_until('#') - chk = "" - chk += self.request.recv(1) - chk += self.request.recv(1) - if len(chk) != 2: - return "" - if int(chk, 16) != self._checksum(pkt): - print >>sys.stderr, "Bad checksum for {0}; got: {1} want: {2:02x}".format(pkt, chk, "want:", self._checksum(pkt)) - self.send_nack() - return "" - - self.send_ack() - return pkt - - def read_until(self, limit): - buf = '' - while True: - ch = self.request.recv(1) - if len(ch) == 0: # eof - return "" - if ch == limit: - return buf - buf += ch - - def send_thread_extra_info(self, tid): - task = self._core.tasks.get(tid) - if task: - self.send_str(binascii.hexlify(str(task))) - else: - self.send_str(binascii.hexlify('[Invalid task 0x%08x]' % tid)) - - - -class TCPServer(SocketServer.TCPServer): - allow_reuse_address = True - -server = TCPServer(('0.0.0.0', args.port), GDBHandler) -print "Waiting for gdb on", args.port -server.serve_forever() From fddc7b2f47bdde348b74a18f9ce6818bbd3f87d3 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 5 Jan 2018 19:42:06 +0300 Subject: [PATCH 132/265] Remove ESP ROM dumps They are generated from bins anyway, so nothing of value is lost. PUBLISHED_FROM=4ada617ffdf52f679ec9b7a7a03a2d64d065cdb0 --- common/platforms/esp32/rom/ESP32_ROM.txt | 172793 ---------------- common/platforms/esp8266/rom/ESP8266_ROM.txt | 25210 --- 2 files changed, 198003 deletions(-) delete mode 100644 common/platforms/esp32/rom/ESP32_ROM.txt delete mode 100644 common/platforms/esp8266/rom/ESP8266_ROM.txt diff --git a/common/platforms/esp32/rom/ESP32_ROM.txt b/common/platforms/esp32/rom/ESP32_ROM.txt deleted file mode 100644 index 08b1b41..0000000 --- a/common/platforms/esp32/rom/ESP32_ROM.txt +++ /dev/null @@ -1,172793 +0,0 @@ - -rom.elf: file format elf32-xtensa-le - - -Disassembly of section .text: - -40000000 <_start>: -40000000: 49c500 s32e a0, a5, -16 -40000003: 49d510 s32e a1, a5, -12 -40000006: 49e520 s32e a2, a5, -8 -40000009: 49f530 s32e a3, a5, -4 -4000000c: 003400 rfwo - ... - -40000010 <_xtos_alloca_handler>: -40000010: 4128 l32i.n a2, a1, 16 -40000012: 5138 l32i.n a3, a1, 20 -40000014: 6148 l32i.n a4, a1, 24 -40000016: 01d112 addmi a1, a1, 0x100 -40000019: 13d100 wsr.excsave1 a0 -4000001c: 034800 rsr.windowbase a0 -4000001f: 4080f0 rotw -1 -40000022: 03e620 rsr.ps a2 -40000025: 343820 extui a3, a2, 8, 4 -40000028: 303340 xor a3, a3, a4 -4000002b: 000846 j 40000050 <_WindowUnderflow4+0x10> - ... - -40000040 <_WindowUnderflow4>: -40000040: 09c500 l32e a0, a5, -16 -40000043: 09d510 l32e a1, a5, -12 -40000046: 09e520 l32e a2, a5, -8 -40000049: 09f530 l32e a3, a5, -4 -4000004c: 003500 rfwu -4000004f: d14000 mul16s a4, a0, a0 -40000052: 338003 lsip f0, a0, 204 -40000055: 223011 l32r a1, 3ffc8918 <_bss_end_btdm+0x89a8> -40000058: e62030 lsi f3, a0, 0x398 -4000005b: 201013 lsi f1, a0, 128 -4000005e: 74f700 extui a15, a0, 7, 8 -40000061: f0dd lsi f13, a0, 0 -40000063: e74080 lsi f8, a0, 0x39c -40000066: 5778 l32i.n a7, a7, 20 -40000068: 4080f0 rotw -1 -4000006b: 003446 j 40000140 <_WindowUnderflow12> - ... - -40000080 <_WindowOverflow8>: -40000080: 49c900 s32e a0, a9, -16 -40000083: 09d100 l32e a0, a1, -12 -40000086: 49d910 s32e a1, a9, -12 -40000089: 49e920 s32e a2, a9, -8 -4000008c: 49f930 s32e a3, a9, -4 -4000008f: 498040 s32e a4, a0, -32 -40000092: 499050 s32e a5, a0, -28 -40000095: 49a060 s32e a6, a0, -24 -40000098: 49b070 s32e a7, a0, -20 -4000009b: 003400 rfwo - ... - -400000c0 <_WindowUnderflow8>: -400000c0: 09c900 l32e a0, a9, -16 -400000c3: 09d910 l32e a1, a9, -12 -400000c6: 09e920 l32e a2, a9, -8 -400000c9: 09d170 l32e a7, a1, -12 -400000cc: 09f930 l32e a3, a9, -4 -400000cf: 098740 l32e a4, a7, -32 -400000d2: 099750 l32e a5, a7, -28 -400000d5: 09a760 l32e a6, a7, -24 -400000d8: 09b770 l32e a7, a7, -20 -400000db: 003500 rfwu - ... - -40000100 <_WindowOverflow12>: -40000100: 49cd00 s32e a0, a13, -16 -40000103: 09d100 l32e a0, a1, -12 -40000106: 49dd10 s32e a1, a13, -12 -40000109: 49ed20 s32e a2, a13, -8 -4000010c: 49fd30 s32e a3, a13, -4 -4000010f: 494040 s32e a4, a0, -48 -40000112: 495050 s32e a5, a0, -44 -40000115: 496060 s32e a6, a0, -40 -40000118: 497070 s32e a7, a0, -36 -4000011b: 498080 s32e a8, a0, -32 -4000011e: 499090 s32e a9, a0, -28 -40000121: 49a0a0 s32e a10, a0, -24 -40000124: 49b0b0 s32e a11, a0, -20 -40000127: 003400 rfwo - ... - -40000140 <_WindowUnderflow12>: -40000140: 09cd00 l32e a0, a13, -16 -40000143: 09dd10 l32e a1, a13, -12 -40000146: 09ed20 l32e a2, a13, -8 -40000149: 09d1b0 l32e a11, a1, -12 -4000014c: 09fd30 l32e a3, a13, -4 -4000014f: 094b40 l32e a4, a11, -48 -40000152: 095b50 l32e a5, a11, -44 -40000155: 096b60 l32e a6, a11, -40 -40000158: 097b70 l32e a7, a11, -36 -4000015b: 098b80 l32e a8, a11, -32 -4000015e: 099b90 l32e a9, a11, -28 -40000161: 09aba0 l32e a10, a11, -24 -40000164: 09bbb0 l32e a11, a11, -20 -40000167: 003500 rfwu -4000016a: 480000 ssx f0, a0, a0 -4000016d: 3ffe04 lsi f0, a14, 252 - ... - -40000180 <_Level2Vector>: -40000180: 61d220 xsr.excsave2 a2 -40000183: 0002a0 jx a2 - ... - -400001c0 <_Level3Vector>: -400001c0: 61d320 xsr.excsave3 a2 -400001c3: 0002a0 jx a2 - ... - -40000200 <_Level4Vector>: -40000200: 61d420 xsr.excsave4 a2 -40000203: 0002a0 jx a2 - ... - -40000240 <_Level5Vector>: -40000240: 61d520 xsr.excsave5 a2 -40000243: 0002a0 jx a2 - ... - -40000280 <_DebugExceptionVector>: -40000280: 13d620 wsr.excsave6 a2 -40000283: 827c movi.n a2, -8 -40000285: 005100 simcall -40000288: ffff06 j 40000288 <_DebugExceptionVector+0x8> - ... - -400002c0 <_NMIExceptionVector>: -400002c0: 003710 rfi 7 - ... - -40000300 <_KernelExceptionVector>: -40000300: 004100 break 1, 0 -40000303: fffe46 j 40000300 <_KernelExceptionVector> - ... - -40000340 <_UserExceptionVector>: -40000340: ffd112 addmi a1, a1, 0xffffff00 -40000343: 4129 s32i.n a2, a1, 16 -40000345: 5139 s32i.n a3, a1, 20 -40000347: ff8931 l32r a3, 4000016c <_WindowUnderflow12+0x2c> -4000034a: 03e820 rsr.exccause a2 -4000034d: a03230 addx4 a3, a2, a3 -40000350: 0338 l32i.n a3, a3, 0 -40000352: 6149 s32i.n a4, a1, 24 -40000354: 0003a0 jx a3 - ... - -400003c0 <_DoubleExceptionVector>: -400003c0: 004140 break 1, 4 -400003c3: fffe46 j 400003c0 <_DoubleExceptionVector> - ... - -40000400 <_ResetVector>: -40000400: 001306 j 40000450 <_ResetHandler> -40000403: abab00 movltz.s f10, f11, a0 -40000406: 380000 lsi f0, a0, 224 -40000409: 3ff000 f64cmph a15, a0, a0, 3 -4000040c: ff .byte 0xff -4000040d: ff .byte 0xff -4000040e: ff .byte 0xff -4000040f: 7f .byte 0x7f -40000410: 000000 ill -40000413: 000000 ill -40000416: 1f4000 f64cmph a4, a0, a0, 1 -40000419: 222221 l32r a2, 3ffc8ca4 <_bss_end_btdm+0x8d34> -4000041c: 000000 ill -4000041f: 04c3e0 extui a12, a14, 3, 1 -40000422: f84000 lsi f0, a0, 0x3e0 -40000425: 4000d4 lsi f13, a0, 0x100 -40000428: d5c8 l32i.n a12, a5, 52 -4000042a: 544000 extui a4, a0, 0, 6 -4000042d: 0009 s32i.n a0, a0, 0 -4000042f: 0a2840 add.s f2, f8, f4 -40000432: f84000 lsi f0, a0, 0x3e0 -40000435: 000a add.n a0, a0, a0 -40000437: 064840 lsi f4, a8, 24 -4000043a: fe .byte 0xfe -4000043b: 3f .byte 0x3f -4000043c: 0c68 l32i.n a6, a12, 0 -4000043e: 4c4000 lsi f0, a0, 0x130 -40000441: 3ffe06 j 4001043d - ... - -40000450 <_ResetHandler>: -40000450: 00a002 movi a0, 0 -40000453: 13e400 wsr.intenable a0 -40000456: 03eb20 rsr.prid a2 -40000459: ffea31 l32r a3, 40000404 <_ResetVector+0x4> -4000045c: 119237 bne a2, a3, 40000471 <_ResetHandler+0x21> -4000045f: ffea31 l32r a3, 40000408 <_ResetVector+0x8> -40000462: 002332 l32i a3, a3, 0 -40000465: 0873f7 bbci a3, 31, 40000471 <_ResetHandler+0x21> -40000468: ffe921 l32r a2, 4000040c <_ResetVector+0xc> -4000046b: 103320 and a3, a3, a2 -4000046e: 0003c0 callx0 a3 -40000471: ffe721 l32r a2, 40000410 <_ResetVector+0x10> -40000474: 03eb30 rsr.prid a3 -40000477: 743030 extui a3, a3, 0, 8 -4000047a: 228c beqz.n a2, 40000480 <_ResetHandler+0x30> -4000047c: 03cc bnez.n a3, 40000480 <_ResetHandler+0x30> -4000047e: 0209 s32i.n a0, a2, 0 -40000480: ffe521 l32r a2, 40000414 <_ResetVector+0x14> -40000483: 13e720 wsr.vecbase a2 -40000486: 531c movi.n a3, 21 -40000488: 136330 wsr.atomctl a3 -4000048b: 006120 rsil a2, 1 -4000048e: ffe221 l32r a2, 40000418 <_ResetVector+0x18> -40000491: ffe251 l32r a5, 4000041c <_ResetVector+0x1c> -40000494: ffe361 l32r a6, 40000420 <_ResetVector+0x20> -40000497: 030c movi.n a3, 0 -40000499: 027d mov.n a7, a2 -4000049b: 106650 and a6, a6, a5 -4000049e: 000846 j 400004c3 <_ResetHandler+0x73> - ... -400004ad: 000000 ill -400004b0: 506340 witlb a4, a3 -400004b3: 002000 isync -400004b6: f03d nop.n -400004b8: f03d nop.n -400004ba: c03350 sub a3, a3, a5 -400004bd: 14b3b6 bltui a3, 16, 400004d5 <_ResetHandler+0x85> -400004c0: 417470 srli a7, a7, 4 -400004c3: 344070 extui a4, a7, 0, 4 -400004c6: e61367 beq a3, a6, 400004b0 <_ResetHandler+0x60> -400004c9: 506340 witlb a4, a3 -400004cc: c03350 sub a3, a3, a5 -400004cf: edb3f6 bgeui a3, 16, 400004c0 <_ResetHandler+0x70> -400004d2: 002000 isync -400004d5: ffd151 l32r a5, 4000041c <_ResetVector+0x1c> -400004d8: 030c movi.n a3, 0 -400004da: 207220 or a7, a2, a2 -400004dd: 344070 extui a4, a7, 0, 4 -400004e0: 50e340 wdtlb a4, a3 -400004e3: c03350 sub a3, a3, a5 -400004e6: 417470 srli a7, a7, 4 -400004e9: f0b3f6 bgeui a3, 16, 400004dd <_ResetHandler+0x8d> -400004ec: 002030 dsync -400004ef: 01a032 movi a3, 1 -400004f2: 036120 rsr.memctl a2 -400004f5: 202230 or a2, a2, a3 -400004f8: 136120 wsr.memctl a2 -400004fb: ffca41 l32r a4, 40000424 <_ResetVector+0x24> -400004fe: ffca51 l32r a5, 40000428 <_ResetVector+0x28> -40000501: 0468 l32i.n a6, a4, 0 -40000503: 1478 l32i.n a7, a4, 4 -40000505: 2488 l32i.n a8, a4, 8 -40000507: 3428 l32i.n a2, a4, 12 -40000509: 081226 beqi a2, 1, 40000515 <_ResetHandler+0xc5> -4000050c: 03eb20 rsr.prid a2 -4000050f: ffbd31 l32r a3, 40000404 <_ResetVector+0x4> -40000512: 0a1237 beq a2, a3, 40000520 <_ResetHandler+0xd0> -40000515: 0828 l32i.n a2, a8, 0 -40000517: 0629 s32i.n a2, a6, 0 -40000519: 664b addi.n a6, a6, 4 -4000051b: 884b addi.n a8, a8, 4 -4000051d: f43677 bltu a6, a7, 40000515 <_ResetHandler+0xc5> -40000520: 10c442 addi a4, a4, 16 -40000523: da3457 bltu a4, a5, 40000501 <_ResetHandler+0xb1> -40000526: 002000 isync -40000529: 110c movi.n a1, 1 -4000052b: 134910 wsr.windowstart a1 -4000052e: 134800 wsr.windowbase a0 -40000531: 002010 rsync -40000534: 000c movi.n a0, 0 -40000536: ffbd41 l32r a4, 4000042c <_ResetVector+0x2c> -40000539: 13d240 wsr.excsave2 a4 -4000053c: ffbd41 l32r a4, 40000430 <_ResetVector+0x30> -4000053f: 13d340 wsr.excsave3 a4 -40000542: ffbc41 l32r a4, 40000434 <_ResetVector+0x34> -40000545: 13d440 wsr.excsave4 a4 -40000548: ffbc51 l32r a5, 40000438 <_ResetVector+0x38> -4000054b: 006542 s32i a4, a5, 0 -4000054e: ffbb41 l32r a4, 4000043c <_ResetVector+0x3c> -40000551: 13d540 wsr.excsave5 a4 -40000554: ffbb51 l32r a5, 40000440 <_ResetVector+0x40> -40000557: 006542 s32i a4, a5, 0 -4000055a: 001a85 call0 40000704 <_stext+0x1a4> -4000055d: 000000 ill - -40000560 <_stext>: -40000560: fe3f20 f64iter a3, a15, a2, 3, 1 -40000563: 3f .byte 0x3f -40000564: 040020 extui a0, a2, 0, 1 -40000567: d5d000 extui a13, a0, 16, 14 -4000056a: 6c4000 lsi f0, a0, 0x1b0 -4000056d: 4000d6 bgez a0, 40000971 <_Level2FromVector+0x1d> -40000570: abab addi.n a10, a11, 10 -40000572: d40000 extui a0, a0, 0, 14 -40000575: bf .byte 0xbf -40000576: 244000 extui a4, a0, 0, 3 -40000579: 4000c0 lsi f12, a0, 0x100 -4000057c: 0de8 l32i.n a14, a13, 0 -4000057e: 484000 ssx f4, a0, a0 -40000581: 3ffe05 call0 40040564 -40000584: 0448 l32i.n a4, a4, 0 -40000586: fe .byte 0xfe -40000587: 3f .byte 0x3f -40000588: 050023 lsi f2, a0, 20 -4000058b: 000700 lsi f0, a7, 0 -4000058e: 058000 extui a8, a0, 16, 1 -40000591: 000000 ill -40000594: 000000 ill -40000597: 0650c0 lsi f12, a0, 24 -4000059a: fe .byte 0xfe -4000059b: 3f .byte 0x3f -4000059c: 000000 ill -4000059f: 065880 lsi f8, a8, 24 -400005a2: fe .byte 0xfe -400005a3: 3f .byte 0x3f -400005a4: 00c034 lsi f3, a0, 0 -400005a7: 000040 lsi f4, a0, 0 -400005aa: 0038 l32i.n a3, a0, 0 -400005ac: 0a19 s32i.n a1, a10, 0 -400005ae: 004000 break 0, 0 -400005b1: c088 l32i.n a8, a0, 48 -400005b3: ea28 l32i.n a2, a10, 56 -400005b5: 000a add.n a0, a0, a0 -400005b7: 0c6040 lsi f4, a0, 48 -400005ba: fe .byte 0xfe -400005bb: 3f .byte 0x3f -400005bc: 0648 l32i.n a4, a6, 0 -400005be: fe .byte 0xfe -400005bf: 3f .byte 0x3f -400005c0: 050024 lsi f2, a0, 20 -400005c3: 000000 ill -400005c6: c05300 sub a5, a3, a0 -400005c9: 3ffe11 l32r a1, 3ffd05c4 <_bss_end_btdm+0x10654> -400005cc: 064c movi.n a6, 64 -400005ce: fe .byte 0xfe -400005cf: 3f .byte 0x3f -400005d0: 050025 call8 400055d4 -400005d3: 000000 ill -400005d6: 008401 l32r a0, 3ffc07e8 <_bss_end_btdm+0x878> -400005d9: 0000f0 callx12 a0 -400005dc: f9c2d4 lsi f13, a2, 0x3e4 -400005df: 3f .byte 0x3f -400005e0: f96024 lsi f2, a0, 0x3e4 -400005e3: 3f .byte 0x3f -400005e4: f96000 lsi f0, a0, 0x3e4 -400005e7: 3f .byte 0x3f -400005e8: f96350 lsi f5, a3, 0x3e4 -400005eb: 3f .byte 0x3f -400005ec: 0e .byte 0xe -400005ed: 000033 lsi f3, a0, 0 -400005f0: abcd lsi f12, a11, 44 -400005f2: ff .byte 0xff -400005f3: ff .byte 0xff -400005f4: 001234 lsi f3, a2, 0 -400005f7: e66d00 lsi f0, a13, 0x398 -400005fa: ff .byte 0xff -400005fb: ff .byte 0xff -400005fc: deec bnez.n a14, 4000062d <_stext+0xcd> -400005fe: ff .byte 0xff -400005ff: ff .byte 0xff -40000600: 000001 l32r a0, 3ffc0600 <_bss_end_btdm+0x690> -40000603: 000000 ill -40000606: 2d0000 lsi f0, a0, 180 -40000609: 7f .byte 0x7f -4000060a: 2d4c95 call4 4002dad4 -4000060d: 5851f4 mula.da.ll.lddec m1, a1, m1, a15 -40000610: ff .byte 0xff -40000611: ff .byte 0xff -40000612: ff .byte 0xff -40000613: 7f .byte 0x7f -40000614: 345987 bbc a9, a8, 4000064c <_stext+0xec> -40000617: 0b5f12 s16i a1, a15, 22 -4000061a: 4e .byte 0x4e -4000061b: 0ce383 lsi f8, a3, 48 -4000061e: fe .byte 0xfe -4000061f: ff .byte 0xff -40000620: 0041a7 ball a1, a10, 40000624 <_stext+0xc4> -40000623: f4ec00 extui a14, a0, 12, 16 -40000626: ff .byte 0xff -40000627: ff .byte 0xff -40000628: ff .byte 0xff -40000629: ef .byte 0xef -4000062a: ff .byte 0xff -4000062b: ff .byte 0xff -4000062c: 001000 movsp a0, a0 -4000062f: 00ff00 lsi f0, a15, 0 -40000632: 000000 ill -40000635: ff .byte 0xff -40000636: 000000 ill -40000639: 00ff00 lsi f0, a15, 0 -4000063c: 000000 ill -4000063f: ff .byte 0xff -40000640: 404040 lsi f4, a0, 0x100 -40000643: 625440 lsi f4, a4, 0x188 -40000646: 3ff9 s32i.n a15, a15, 12 -40000648: 1f .byte 0x1f -40000649: 51eb85 call0 40052504 -4000064c: 609c beqz.n a0, 40000666 <_stext+0x106> -4000064e: 3ff9 s32i.n a15, a15, 12 -40000650: 492493 lsi f9, a4, 0x124 -40000653: ffff92 s32ri a9, a15, 0x3fc -40000656: ff .byte 0xff -40000657: 3f .byte 0x3f -40000658: 015180 slli a5, a1, 24 -4000065b: e08000 subx4 a8, a0, a0 -4000065e: 3ffa add.n a3, a15, a15 -40000660: f9c4a6 blti a4, 32, 4000065d <_stext+0xfd> -40000663: 3f .byte 0x3f -40000664: fae0a0 rsqrt0.s f14, f0 -40000667: 3f .byte 0x3f -40000668: fae0a4 lsi f10, a0, 0x3e8 -4000066b: 3f .byte 0x3f -4000066c: fae030 const.s f14, 0 -4000066f: 3f .byte 0x3f -40000670: c4a9 s32i.n a10, a4, 48 -40000672: 3ff9 s32i.n a15, a15, 12 -40000674: fae084 lsi f8, a0, 0x3e8 -40000677: 3f .byte 0x3f -40000678: c4ad lsi f10, a4, 16 -4000067a: 3ff9 s32i.n a15, a15, 12 -4000067c: fae093 lsi f9, a0, 0x3e8 -4000067f: 3f .byte 0x3f -40000680: f9c4d0 lsi f13, a4, 0x3e4 -40000683: 3f .byte 0x3f -40000684: e088 l32i.n a8, a0, 56 -40000686: 3ffa add.n a3, a15, a15 -40000688: fff1f0 f64cmph a15, a1, a15, 15 -4000068b: ff .byte 0xff -4000068c: c4bc beqz.n a4, 400006cc <_stext+0x16c> -4000068e: 3ff9 s32i.n a15, a15, 12 -40000690: cf .byte 0xcf -40000691: 3ff9c4 lsi f12, a9, 252 -40000694: 1fec bnez.n a15, 400006b9 <_stext+0x159> -40000696: 184000 lsxp f4, a0, a0 -40000699: 400011 l32r a1, 3ffd069c <_bss_end_btdm+0x1072c> -4000069c: 001150 movsp a5, a1 -4000069f: 118440 slli a8, a4, 12 -400006a2: b84000 lsi f0, a0, 0x2e0 -400006a5: 400011 l32r a1, 3ffd06a8 <_bss_end_btdm+0x10738> -400006a8: fae0b0 nexp01.s f14, f0 -400006ab: 3f .byte 0x3f -400006ac: e0ac beqz.n a0, 400006de <_stext+0x17e> -400006ae: 3ffa add.n a3, a15, a15 -400006b0: e0a8 l32i.n a10, a0, 56 -400006b2: 3ffa add.n a3, a15, a15 -400006b4: 1d48 l32i.n a4, a13, 4 -400006b6: 584000 ssxp f4, a0, a0 -400006b9: 001d mov.n a1, a0 -400006bb: 1d7040 lsi f4, a0, 116 -400006be: b44000 extui a4, a0, 0, 12 -400006c1: 3ffae0 f64cmph a15, a10, a14, 3 -400006c4: e038 l32i.n a3, a0, 56 -400006c6: 3ffa add.n a3, a15, a15 -400006c8: e0b8 l32i.n a11, a0, 56 -400006ca: 3ffa add.n a3, a15, a15 -400006cc: 6498 l32i.n a9, a4, 24 -400006ce: 3ff9 s32i.n a15, a15, 12 -400006d0: 6478 l32i.n a7, a4, 24 -400006d2: 3ff9 s32i.n a15, a15, 12 -400006d4: 6458 l32i.n a5, a4, 24 -400006d6: 3ff9 s32i.n a15, a15, 12 -400006d8: 800000 add a0, a0, a0 -400006db: 7f .byte 0x7f -400006dc: 400000 ssr a0 -400006df: ffff00 f64cmph a15, a15, a0, 15 -400006e2: ff .byte 0xff -400006e3: 000000 ill -400006e6: 007ff0 sddr32.p a15 -400006e9: 000800 lsi f0, a8, 0 -400006ec: ff .byte 0xff -400006ed: ff .byte 0xff -400006ee: 1f .byte 0x1f -400006ef: 000000 ill -400006f2: 443800 extui a3, a0, 8, 5 -400006f5: 3ff965 call8 4004068c -400006f8: 006996 bltz a9, 40000702 <_stext+0x1a2> -400006fb: c2b400 quou a11, a4, a0 -400006fe: 3ff9 s32i.n a15, a15, 12 -40000700: c01c movi.n a0, 28 -40000702: 0c4000 lsi f0, a0, 48 -40000705: 961100 lsi f0, a1, 0x258 -40000708: ff .byte 0xff -40000709: ff9631 l32r a3, 40000564 <_stext+0x4> -4000070c: 13e630 wsr.ps a3 -4000070f: 002010 rsync -40000712: ff9561 l32r a6, 40000568 <_stext+0x8> -40000715: ff9571 l32r a7, 4000056c <_stext+0xc> -40000718: 000c movi.n a0, 0 -4000071a: 0648 l32i.n a4, a6, 0 -4000071c: 1658 l32i.n a5, a6, 4 -4000071e: 2638 l32i.n a3, a6, 8 -40000720: 111326 beqi a3, 1, 40000735 <_stext+0x1d5> -40000723: 03eb20 rsr.prid a2 -40000726: ff9231 l32r a3, 40000570 <_stext+0x10> -40000729: 0b1237 beq a2, a3, 40000738 <_stext+0x1d8> -4000072c: 000146 j 40000735 <_stext+0x1d5> -4000072f: 090000 l32e a0, a0, -64 -40000732: 444b04 lsi f0, a11, 0x110 -40000735: f83457 bltu a4, a5, 40000731 <_stext+0x1d1> -40000738: 66cb addi.n a6, a6, 12 -4000073a: dc3677 bltu a6, a7, 4000071a <_stext+0x1ba> -4000073d: 06f855 call4 400076c4 -40000740: 120c movi.n a2, 1 -40000742: 005100 simcall -40000745: 0041f0 break 1, 15 -40000748: fffd06 j 40000740 <_stext+0x1e0> - ... - -4000074c <_xtos_set_exception_handler>: -4000074c: 004136 entry a1, 32 -4000074f: f83c movi.n a8, 63 -40000751: 03b827 bgeu a8, a2, 40000758 <_xtos_set_exception_handler+0xc> -40000754: 020c movi.n a2, 0 -40000756: f01d retw.n -40000758: ff8aa1 l32r a10, 40000580 <_stext+0x20> -4000075b: 1182e0 slli a8, a2, 2 -4000075e: 23ac beqz.n a3, 40000784 <_xtos_set_exception_handler+0x38> -40000760: ff8591 l32r a9, 40000574 <_stext+0x14> -40000763: 2a8a add.n a2, a10, a8 -40000765: 002222 l32i a2, a2, 0 -40000768: ff85b1 l32r a11, 4000057c <_stext+0x1c> -4000076b: 059397 bne a3, a9, 40000774 <_xtos_set_exception_handler+0x28> -4000076e: ff82b1 l32r a11, 40000578 <_stext+0x18> -40000771: 203990 or a3, a9, a9 -40000774: ff84c1 l32r a12, 40000584 <_stext+0x24> -40000777: aa8a add.n a10, a10, a8 -40000779: 8c8a add.n a8, a12, a8 -4000077b: 08b9 s32i.n a11, a8, 0 -4000077d: 0a39 s32i.n a3, a10, 0 -4000077f: d11297 beq a2, a9, 40000754 <_xtos_set_exception_handler+0x8> -40000782: f01d retw.n -40000784: 2a8a add.n a2, a10, a8 -40000786: 0228 l32i.n a2, a2, 0 -40000788: ff7b91 l32r a9, 40000574 <_stext+0x14> -4000078b: fff7c6 j 4000076e <_xtos_set_exception_handler+0x22> - ... - -40000790 <_xtos_syscall_handler>: -40000790: 03b130 rsr.epc1 a3 -40000793: 030120 rsr.lend a2 -40000796: 333b addi.n a3, a3, 3 -40000798: 0c9237 bne a2, a3, 400007a8 <_xtos_syscall_handler+0x18> -4000079b: 030220 rsr.lcount a2 -4000079e: 628c beqz.n a2, 400007a8 <_xtos_syscall_handler+0x18> -400007a0: 220b addi.n a2, a2, -1 -400007a2: 130220 wsr.lcount a2 -400007a5: 030030 rsr.lbeg a3 -400007a8: 4128 l32i.n a2, a1, 16 -400007aa: 13b130 wsr.epc1 a3 -400007ad: 5138 l32i.n a3, a1, 20 -400007af: 056256 bnez a2, 40000809 <_SyscallException+0x3a> -400007b2: 396132 s32i a3, a1, 228 -400007b5: 3a6142 s32i a4, a1, 232 -400007b8: 3b6152 s32i a5, a1, 236 -400007bb: ff7331 l32r a3, 40000588 <_stext+0x28> -400007be: 03e620 rsr.ps a2 -400007c1: 13e630 wsr.ps a3 -400007c4: 03b130 rsr.epc1 a3 -400007c7: 01d112 addmi a1, a1, 0x100 -400007ca: 002010 rsync -400007cd: 040c movi.n a4, 0 - -400007cf <_SyscallException>: -400007cf: 008136 entry a1, 64 -400007d2: 0001f5 call12 400007f0 <_SyscallException+0x21> -400007d5: ff6de1 l32r a14, 4000058c <_stext+0x2c> -400007d8: 0cea add.n a0, a12, a14 -400007da: f01d retw.n -400007dc: 13e620 wsr.ps a2 -400007df: 020c movi.n a2, 0 -400007e1: a548 l32i.n a4, a5, 40 -400007e3: 002010 rsync -400007e6: 13b130 wsr.epc1 a3 -400007e9: 9538 l32i.n a3, a5, 36 -400007eb: b558 l32i.n a5, a5, 44 -400007ed: 003000 rfe -400007f0: 006136 entry a1, 48 -400007f3: ff67c1 l32r a12, 40000590 <_stext+0x30> -400007f6: c0ca add.n a12, a0, a12 -400007f8: 006136 entry a1, 48 -400007fb: 00cd mov.n a12, a0 -400007fd: 006136 entry a1, 48 -40000800: 00cd mov.n a12, a0 -40000802: 002136 entry a1, 16 -40000805: 0bbd mov.n a11, a11 -40000807: f01d retw.n -40000809: f27c movi.n a2, -1 -4000080b: 01d112 addmi a1, a1, 0x100 -4000080e: 003000 rfe -40000811: 000000 ill - -40000814 <_xtos_l1int_handler>: -40000814: 7159 s32i.n a5, a1, 28 -40000816: ff5c21 l32r a2, 40000588 <_stext+0x28> -40000819: 03b130 rsr.epc1 a3 -4000081c: 61e620 xsr.ps a2 -4000081f: 0139 s32i.n a3, a1, 0 -40000821: 1129 s32i.n a2, a1, 4 -40000823: 3b2122 l32i a2, a1, 236 -40000826: 01d112 addmi a1, a1, 0x100 -40000829: 002010 rsync -4000082c: ff5a41 l32r a4, 40000594 <_stext+0x34> -4000082f: 203430 or a3, a4, a3 -40000832: 904430 addx2 a4, a4, a3 - -40000835 <_LevelOneInterrupt>: -40000835: 020136 entry a1, 0x100 -40000838: 0061f0 rsil a15, 1 -4000083b: ff57e1 l32r a14, 40000598 <_stext+0x38> -4000083e: 03e2f0 rsr.interrupt a15 -40000841: 03e4c0 rsr.intenable a12 -40000844: 1ed8 l32i.n a13, a14, 4 -40000846: 10ffc0 and a15, a15, a12 -40000849: 0303c0 rsr.sar a12 -4000084c: 31d9 s32i.n a13, a1, 12 -4000084e: 092f16 beqz a15, 400008e4 <_LevelOneInterrupt+0xaf> -40000851: 21c9 s32i.n a12, a1, 8 -40000853: 8129 s32i.n a2, a1, 32 -40000855: ffaf22 movi a2, -1 -40000858: 40ffc0 nsau a12, a15 -4000085b: ff50f1 l32r a15, 4000059c <_stext+0x3c> -4000085e: 400c00 ssr a12 -40000861: 91f0f0 srl a15, a15 -40000864: 3022f0 xor a2, a2, a15 -40000867: ff4ed1 l32r a13, 400005a0 <_stext+0x40> -4000086a: 13e3f0 wsr.intclear a15 -4000086d: b0ccd0 addx8 a12, a12, a13 -40000870: 402cd2 l32i a13, a12, 0x100 -40000873: 0066f0 rsil a15, 6 -40000876: 0ef8 l32i.n a15, a14, 0 -40000878: 1ed9 s32i.n a13, a14, 4 -4000087a: 10ffd0 and a15, a15, a13 -4000087d: 13e4f0 wsr.intenable a15 -40000880: 002010 rsync -40000883: 0060f0 rsil a15, 0 -40000886: 0302d0 rsr.lcount a13 -40000889: 0300f0 rsr.lbeg a15 -4000088c: 91d9 s32i.n a13, a1, 36 -4000088e: 0301d0 rsr.lend a13 -40000891: a1f9 s32i.n a15, a1, 40 -40000893: b1d9 s32i.n a13, a1, 44 -40000895: 0310d0 rsr.acclo a13 -40000898: 0311f0 rsr.acchi a15 -4000089b: c1d9 s32i.n a13, a1, 48 -4000089d: d1f9 s32i.n a15, a1, 52 -4000089f: 0cd8 l32i.n a13, a12, 0 -400008a1: 01fd mov.n a15, a1 -400008a3: 012ce2 l32i a14, a12, 4 -400008a6: 000df0 callx12 a13 -400008a9: 91d8 l32i.n a13, a1, 36 -400008ab: a1e8 l32i.n a14, a1, 40 -400008ad: b1f8 l32i.n a15, a1, 44 -400008af: 1302d0 wsr.lcount a13 -400008b2: 1300e0 wsr.lbeg a14 -400008b5: 1301f0 wsr.lend a15 -400008b8: c1d8 l32i.n a13, a1, 48 -400008ba: d1e8 l32i.n a14, a1, 52 -400008bc: 1310d0 wsr.acclo a13 -400008bf: 1311e0 wsr.acchi a14 -400008c2: ff35e1 l32r a14, 40000598 <_stext+0x38> -400008c5: 03e2f0 rsr.interrupt a15 -400008c8: 0066d0 rsil a13, 6 -400008cb: 0ed8 l32i.n a13, a14, 0 -400008cd: 31c8 l32i.n a12, a1, 12 -400008cf: 10ddc0 and a13, a13, a12 -400008d2: 10ffd0 and a15, a15, a13 -400008d5: 01ff56 bnez a15, 400008f8 <_LevelOneInterrupt+0xc3> -400008d8: 8128 l32i.n a2, a1, 32 -400008da: 1ec9 s32i.n a12, a14, 4 -400008dc: 21c8 l32i.n a12, a1, 8 -400008de: 13e4d0 wsr.intenable a13 -400008e1: 0063d0 rsil a13, 3 -400008e4: ff3001 l32r a0, 400005a4 <_stext+0x44> -400008e7: ff2bd1 l32r a13, 40000594 <_stext+0x34> -400008ea: 1303c0 wsr.sar a12 -400008ed: 2000d0 or a0, a0, a13 -400008f0: 900d00 addx2 a0, a13, a0 -400008f3: 0063d0 rsil a13, 3 -400008f6: f01d retw.n -400008f8: 40ffd0 nsau a13, a15 -400008fb: ff29c1 l32r a12, 400005a0 <_stext+0x40> -400008fe: b0cdc0 addx8 a12, a13, a12 -40000901: 412ce2 l32i a14, a12, 0x104 -40000904: 10ff20 and a15, a15, a2 -40000907: 10ffe0 and a15, a15, a14 -4000090a: ff23e1 l32r a14, 40000598 <_stext+0x38> -4000090d: f47f56 bnez a15, 40000858 <_LevelOneInterrupt+0x23> -40000910: ff23f1 l32r a15, 4000059c <_stext+0x3c> -40000913: 400d00 ssr a13 -40000916: 91d0f0 srl a13, a15 -40000919: 412cf2 l32i a15, a12, 0x104 -4000091c: 13e3d0 wsr.intclear a13 -4000091f: 2022f0 or a2, a2, a15 -40000922: 3022d0 xor a2, a2, a13 -40000925: ffd1c6 j 40000870 <_LevelOneInterrupt+0x3b> - -40000928 <_xtos_restore_intlevel>: -40000928: 002136 entry a1, 16 -4000092b: 13e620 wsr.ps a2 -4000092e: 002010 rsync -40000931: f01d retw.n - ... - -40000934 <_xtos_set_vpri>: -40000934: 002136 entry a1, 16 -40000937: 023d mov.n a3, a2 -40000939: ff1741 l32r a4, 40000598 <_stext+0x38> -4000093c: 006670 rsil a7, 6 -4000093f: 1428 l32i.n a2, a4, 4 -40000941: 0458 l32i.n a5, a4, 0 -40000943: 1439 s32i.n a3, a4, 4 -40000945: 105530 and a5, a5, a3 -40000948: 13e450 wsr.intenable a5 -4000094b: 13e670 wsr.ps a7 -4000094e: 002010 rsync -40000951: f01d retw.n - ... - -40000954 <_Level2FromVector>: -40000954: 61d220 xsr.excsave2 a2 -40000957: ffd112 addmi a1, a1, 0xffffff00 -4000095a: 4129 s32i.n a2, a1, 16 -4000095c: ff0b21 l32r a2, 40000588 <_stext+0x28> -4000095f: 6149 s32i.n a4, a1, 24 -40000961: 7159 s32i.n a5, a1, 28 -40000963: 13e620 wsr.ps a2 -40000966: 002010 rsync -40000969: 3b2122 l32i a2, a1, 236 -4000096c: 01d112 addmi a1, a1, 0x100 -4000096f: 03b240 rsr.epc2 a4 -40000972: ff0851 l32r a5, 40000594 <_stext+0x34> -40000975: 204540 or a4, a5, a4 -40000978: 904540 addx2 a4, a5, a4 -4000097b: 020136 entry a1, 0x100 -4000097e: 0062f0 rsil a15, 2 -40000981: 03e2f0 rsr.interrupt a15 -40000984: 03e4c0 rsr.intenable a12 -40000987: ff08d1 l32r a13, 400005a8 <_stext+0x48> -4000098a: 10ffc0 and a15, a15, a12 -4000098d: 10ffd0 and a15, a15, a13 -40000990: 0303e0 rsr.sar a14 -40000993: 06ef16 beqz a15, 40000a05 <_Level2FromVector+0xb1> -40000996: 21e9 s32i.n a14, a1, 8 -40000998: 0302d0 rsr.lcount a13 -4000099b: 0300e0 rsr.lbeg a14 -4000099e: 91d9 s32i.n a13, a1, 36 -400009a0: 0301d0 rsr.lend a13 -400009a3: a1e9 s32i.n a14, a1, 40 -400009a5: b1d9 s32i.n a13, a1, 44 -400009a7: 0310d0 rsr.acclo a13 -400009aa: 0311e0 rsr.acchi a14 -400009ad: c1d9 s32i.n a13, a1, 48 -400009af: d1e9 s32i.n a14, a1, 52 -400009b1: 60c0f0 neg a12, a15 -400009b4: 10ccf0 and a12, a12, a15 -400009b7: 13e3c0 wsr.intclear a12 -400009ba: fef9d1 l32r a13, 400005a0 <_stext+0x40> -400009bd: fe1c movi.n a14, 31 -400009bf: 40fcc0 nsau a12, a12 -400009c2: c0fec0 sub a15, a14, a12 -400009c5: 60f0f0 neg a15, a15 -400009c8: 1fcff2 addi a15, a15, 31 -400009cb: b0cfd0 addx8 a12, a15, a13 -400009ce: 0cd8 l32i.n a13, a12, 0 -400009d0: 1ce8 l32i.n a14, a12, 4 -400009d2: 20f110 or a15, a1, a1 -400009d5: 000df0 callx12 a13 -400009d8: 03e2f0 rsr.interrupt a15 -400009db: 03e4c0 rsr.intenable a12 -400009de: fef2d1 l32r a13, 400005a8 <_stext+0x48> -400009e1: 10ffc0 and a15, a15, a12 -400009e4: 10ffd0 and a15, a15, a13 -400009e7: fc6f56 bnez a15, 400009b1 <_Level2FromVector+0x5d> -400009ea: 91d8 l32i.n a13, a1, 36 -400009ec: a1e8 l32i.n a14, a1, 40 -400009ee: b1f8 l32i.n a15, a1, 44 -400009f0: 1302d0 wsr.lcount a13 -400009f3: 1300e0 wsr.lbeg a14 -400009f6: 1301f0 wsr.lend a15 -400009f9: c1d8 l32i.n a13, a1, 48 -400009fb: d1e8 l32i.n a14, a1, 52 -400009fd: 1310d0 wsr.acclo a13 -40000a00: 1311e0 wsr.acchi a14 -40000a03: 21e8 l32i.n a14, a1, 8 -40000a05: fee901 l32r a0, 400005ac <_stext+0x4c> -40000a08: fee3d1 l32r a13, 40000594 <_stext+0x34> -40000a0b: 1303e0 wsr.sar a14 -40000a0e: 2000d0 or a0, a0, a13 -40000a11: 900d00 addx2 a0, a13, a0 -40000a14: 0063e0 rsil a14, 3 -40000a17: f01d retw.n -40000a19: 3b6522 s32i a2, a5, 236 -40000a1c: 4528 l32i.n a2, a5, 16 -40000a1e: 6548 l32i.n a4, a5, 24 -40000a20: 7558 l32i.n a5, a5, 28 -40000a22: 003210 rfi 2 -40000a25: 000000 ill - -40000a28 <_Level3FromVector>: -40000a28: 61d320 xsr.excsave3 a2 -40000a2b: ffd112 addmi a1, a1, 0xffffff00 -40000a2e: 4129 s32i.n a2, a1, 16 -40000a30: fed621 l32r a2, 40000588 <_stext+0x28> -40000a33: 6149 s32i.n a4, a1, 24 -40000a35: 7159 s32i.n a5, a1, 28 -40000a37: 13e620 wsr.ps a2 -40000a3a: 002010 rsync -40000a3d: 3b2122 l32i a2, a1, 236 -40000a40: 01d112 addmi a1, a1, 0x100 -40000a43: 03b340 rsr.epc3 a4 -40000a46: fed351 l32r a5, 40000594 <_stext+0x34> -40000a49: 204540 or a4, a5, a4 -40000a4c: 904540 addx2 a4, a5, a4 -40000a4f: 020136 entry a1, 0x100 -40000a52: 0063f0 rsil a15, 3 -40000a55: 03e2f0 rsr.interrupt a15 -40000a58: 03e4c0 rsr.intenable a12 -40000a5b: fed5d1 l32r a13, 400005b0 <_stext+0x50> -40000a5e: 10ffc0 and a15, a15, a12 -40000a61: 10ffd0 and a15, a15, a13 -40000a64: 0303e0 rsr.sar a14 -40000a67: 06ef16 beqz a15, 40000ad9 <_Level3FromVector+0xb1> -40000a6a: 21e9 s32i.n a14, a1, 8 -40000a6c: 0302d0 rsr.lcount a13 -40000a6f: 0300e0 rsr.lbeg a14 -40000a72: 91d9 s32i.n a13, a1, 36 -40000a74: 0301d0 rsr.lend a13 -40000a77: a1e9 s32i.n a14, a1, 40 -40000a79: b1d9 s32i.n a13, a1, 44 -40000a7b: 0310d0 rsr.acclo a13 -40000a7e: 0311e0 rsr.acchi a14 -40000a81: c1d9 s32i.n a13, a1, 48 -40000a83: d1e9 s32i.n a14, a1, 52 -40000a85: 60c0f0 neg a12, a15 -40000a88: 10ccf0 and a12, a12, a15 -40000a8b: 13e3c0 wsr.intclear a12 -40000a8e: fec4d1 l32r a13, 400005a0 <_stext+0x40> -40000a91: fe1c movi.n a14, 31 -40000a93: 40fcc0 nsau a12, a12 -40000a96: c0fec0 sub a15, a14, a12 -40000a99: 60f0f0 neg a15, a15 -40000a9c: 1fcff2 addi a15, a15, 31 -40000a9f: b0cfd0 addx8 a12, a15, a13 -40000aa2: 0cd8 l32i.n a13, a12, 0 -40000aa4: 1ce8 l32i.n a14, a12, 4 -40000aa6: 20f110 or a15, a1, a1 -40000aa9: 000df0 callx12 a13 -40000aac: 03e2f0 rsr.interrupt a15 -40000aaf: 03e4c0 rsr.intenable a12 -40000ab2: febfd1 l32r a13, 400005b0 <_stext+0x50> -40000ab5: 10ffc0 and a15, a15, a12 -40000ab8: 10ffd0 and a15, a15, a13 -40000abb: fc6f56 bnez a15, 40000a85 <_Level3FromVector+0x5d> -40000abe: 91d8 l32i.n a13, a1, 36 -40000ac0: a1e8 l32i.n a14, a1, 40 -40000ac2: b1f8 l32i.n a15, a1, 44 -40000ac4: 1302d0 wsr.lcount a13 -40000ac7: 1300e0 wsr.lbeg a14 -40000aca: 1301f0 wsr.lend a15 -40000acd: c1d8 l32i.n a13, a1, 48 -40000acf: d1e8 l32i.n a14, a1, 52 -40000ad1: 1310d0 wsr.acclo a13 -40000ad4: 1311e0 wsr.acchi a14 -40000ad7: 21e8 l32i.n a14, a1, 8 -40000ad9: feb601 l32r a0, 400005b4 <_stext+0x54> -40000adc: feaed1 l32r a13, 40000594 <_stext+0x34> -40000adf: 1303e0 wsr.sar a14 -40000ae2: 2000d0 or a0, a0, a13 -40000ae5: 900d00 addx2 a0, a13, a0 -40000ae8: f01d retw.n -40000aea: 3b6522 s32i a2, a5, 236 -40000aed: 4528 l32i.n a2, a5, 16 -40000aef: 6548 l32i.n a4, a5, 24 -40000af1: 7558 l32i.n a5, a5, 28 -40000af3: 003310 rfi 3 - ... - -40000af8 <_Level4FromVector>: -40000af8: feb021 l32r a2, 400005b8 <_stext+0x58> -40000afb: d209 s32i.n a0, a2, 52 -40000afd: feaf01 l32r a0, 400005bc <_stext+0x5c> -40000b00: e219 s32i.n a1, a2, 56 -40000b02: 0008 l32i.n a0, a0, 0 -40000b04: 106232 s32i a3, a2, 64 -40000b07: 61d400 xsr.excsave4 a0 -40000b0a: 116242 s32i a4, a2, 68 -40000b0d: f209 s32i.n a0, a2, 60 -40000b0f: 03b130 rsr.epc1 a3 -40000b12: 03e840 rsr.exccause a4 -40000b15: 3239 s32i.n a3, a2, 12 -40000b17: 4249 s32i.n a4, a2, 16 -40000b19: 03ee30 rsr.excvaddr a3 -40000b1c: 056232 s32i a3, a2, 20 -40000b1f: 03d140 rsr.excsave1 a4 -40000b22: 6249 s32i.n a4, a2, 24 -40000b24: 38a002 movi a0, 56 -40000b27: 126252 s32i a5, a2, 72 -40000b2a: 136262 s32i a6, a2, 76 -40000b2d: 146272 s32i a7, a2, 80 -40000b30: 156282 s32i a8, a2, 84 -40000b33: 166292 s32i a9, a2, 88 -40000b36: 1762a2 s32i a10, a2, 92 -40000b39: 1862b2 s32i a11, a2, 96 -40000b3c: 1962c2 s32i a12, a2, 100 -40000b3f: 1a62d2 s32i a13, a2, 104 -40000b42: 1b62e2 s32i a14, a2, 108 -40000b45: 1c62f2 s32i a15, a2, 112 -40000b48: f8c082 addi a8, a0, -8 -40000b4b: 20c2a2 addi a10, a2, 32 -40000b4e: 408020 rotw 2 -40000b51: fdb056 bnez a0, 40000b30 <_Level4FromVector+0x38> -40000b54: 408020 rotw 2 -40000b57: 034930 rsr.windowstart a3 -40000b5a: 034840 rsr.windowbase a4 -40000b5d: 1239 s32i.n a3, a2, 4 -40000b5f: 2249 s32i.n a4, a2, 8 -40000b61: 130c movi.n a3, 1 -40000b63: 040c movi.n a4, 0 -40000b65: 134930 wsr.windowstart a3 -40000b68: 134840 wsr.windowbase a4 -40000b6b: 002010 rsync -40000b6e: fe9211 l32r a1, 400005b8 <_stext+0x58> -40000b71: 000c movi.n a0, 0 -40000b73: fe9321 l32r a2, 400005c0 <_stext+0x60> -40000b76: 13e620 wsr.ps a2 -40000b79: 002010 rsync -40000b7c: 0303e0 rsr.sar a14 -40000b7f: 01e9 s32i.n a14, a1, 0 -40000b81: 0302e0 rsr.lcount a14 -40000b84: a1e9 s32i.n a14, a1, 40 -40000b86: 0300e0 rsr.lbeg a14 -40000b89: b1e9 s32i.n a14, a1, 44 -40000b8b: 0301e0 rsr.lend a14 -40000b8e: c1e9 s32i.n a14, a1, 48 -40000b90: 0310e0 rsr.acclo a14 -40000b93: 81e9 s32i.n a14, a1, 32 -40000b95: 0311e0 rsr.acchi a14 -40000b98: 91e9 s32i.n a14, a1, 36 -40000b9a: 03e2f0 rsr.interrupt a15 -40000b9d: 03e4c0 rsr.intenable a12 -40000ba0: fe89d1 l32r a13, 400005c4 <_stext+0x64> -40000ba3: 10ffc0 and a15, a15, a12 -40000ba6: 10ffd0 and a15, a15, a13 -40000ba9: 02af16 beqz a15, 40000bd7 <_Level4FromVector+0xdf> -40000bac: 60e0f0 neg a14, a15 -40000baf: 10eef0 and a14, a14, a15 -40000bb2: 13e3e0 wsr.intclear a14 -40000bb5: fe7ac1 l32r a12, 400005a0 <_stext+0x40> -40000bb8: 40fee0 nsau a14, a14 -40000bbb: b0cec0 addx8 a12, a14, a12 -40000bbe: 0cd8 l32i.n a13, a12, 0 -40000bc0: 1c68 l32i.n a6, a12, 4 -40000bc2: 000dd0 callx4 a13 -40000bc5: 03e2f0 rsr.interrupt a15 -40000bc8: 03e4c0 rsr.intenable a12 -40000bcb: fe7ed1 l32r a13, 400005c4 <_stext+0x64> -40000bce: 10ffc0 and a15, a15, a12 -40000bd1: 10ffd0 and a15, a15, a13 -40000bd4: fd4f56 bnez a15, 40000bac <_Level4FromVector+0xb4> -40000bd7: a1d8 l32i.n a13, a1, 40 -40000bd9: b1e8 l32i.n a14, a1, 44 -40000bdb: c1f8 l32i.n a15, a1, 48 -40000bdd: 1302d0 wsr.lcount a13 -40000be0: 1300e0 wsr.lbeg a14 -40000be3: 1301f0 wsr.lend a15 -40000be6: 81d8 l32i.n a13, a1, 32 -40000be8: 91e8 l32i.n a14, a1, 36 -40000bea: 1310d0 wsr.acclo a13 -40000bed: 1311e0 wsr.acchi a14 -40000bf0: 01f8 l32i.n a15, a1, 0 -40000bf2: 1303f0 wsr.sar a15 -40000bf5: 423c movi.n a2, 52 -40000bf7: 13e620 wsr.ps a2 -40000bfa: 002010 rsync -40000bfd: 1128 l32i.n a2, a1, 4 -40000bff: 022132 l32i a3, a1, 8 -40000c02: 134920 wsr.windowstart a2 -40000c05: 134830 wsr.windowbase a3 -40000c08: 002010 rsync -40000c0b: fe6b11 l32r a1, 400005b8 <_stext+0x58> -40000c0e: 38a062 movi a6, 56 -40000c11: e0c172 addi a7, a1, -32 -40000c14: f8c6e2 addi a14, a6, -8 -40000c17: 20c7f2 addi a15, a7, 32 -40000c1a: 112f42 l32i a4, a15, 68 -40000c1d: 122f52 l32i a5, a15, 72 -40000c20: 132f62 l32i a6, a15, 76 -40000c23: 142f72 l32i a7, a15, 80 -40000c26: 152f82 l32i a8, a15, 84 -40000c29: 162f92 l32i a9, a15, 88 -40000c2c: 172fa2 l32i a10, a15, 92 -40000c2f: 182fb2 l32i a11, a15, 96 -40000c32: 408020 rotw 2 -40000c35: fdb656 bnez a6, 40000c14 <_Level4FromVector+0x11c> -40000c38: 192742 l32i a4, a7, 100 -40000c3b: 1a2752 l32i a5, a7, 104 -40000c3e: 1b2762 l32i a6, a7, 108 -40000c41: 1c2772 l32i a7, a7, 112 -40000c44: 408020 rotw 2 -40000c47: 3128 l32i.n a2, a1, 12 -40000c49: 4138 l32i.n a3, a1, 16 -40000c4b: 13b120 wsr.epc1 a2 -40000c4e: 13e830 wsr.exccause a3 -40000c51: 5128 l32i.n a2, a1, 20 -40000c53: 13ee20 wsr.excvaddr a2 -40000c56: 6138 l32i.n a3, a1, 24 -40000c58: 13d130 wsr.excsave1 a3 -40000c5b: d108 l32i.n a0, a1, 52 -40000c5d: f128 l32i.n a2, a1, 60 -40000c5f: 102132 l32i a3, a1, 64 -40000c62: e118 l32i.n a1, a1, 56 -40000c64: 003410 rfi 4 - ... - -40000c68 <_Level5FromVector>: -40000c68: fe5821 l32r a2, 400005c8 <_stext+0x68> -40000c6b: d209 s32i.n a0, a2, 52 -40000c6d: fe5701 l32r a0, 400005cc <_stext+0x6c> -40000c70: e219 s32i.n a1, a2, 56 -40000c72: 0008 l32i.n a0, a0, 0 -40000c74: 106232 s32i a3, a2, 64 -40000c77: 61d500 xsr.excsave5 a0 -40000c7a: 116242 s32i a4, a2, 68 -40000c7d: f209 s32i.n a0, a2, 60 -40000c7f: 03b130 rsr.epc1 a3 -40000c82: 03e840 rsr.exccause a4 -40000c85: 3239 s32i.n a3, a2, 12 -40000c87: 4249 s32i.n a4, a2, 16 -40000c89: 03ee30 rsr.excvaddr a3 -40000c8c: 056232 s32i a3, a2, 20 -40000c8f: 03d140 rsr.excsave1 a4 -40000c92: 6249 s32i.n a4, a2, 24 -40000c94: 38a002 movi a0, 56 -40000c97: 126252 s32i a5, a2, 72 -40000c9a: 136262 s32i a6, a2, 76 -40000c9d: 146272 s32i a7, a2, 80 -40000ca0: 156282 s32i a8, a2, 84 -40000ca3: 166292 s32i a9, a2, 88 -40000ca6: 1762a2 s32i a10, a2, 92 -40000ca9: 1862b2 s32i a11, a2, 96 -40000cac: 1962c2 s32i a12, a2, 100 -40000caf: 1a62d2 s32i a13, a2, 104 -40000cb2: 1b62e2 s32i a14, a2, 108 -40000cb5: 1c62f2 s32i a15, a2, 112 -40000cb8: f8c082 addi a8, a0, -8 -40000cbb: 20c2a2 addi a10, a2, 32 -40000cbe: 408020 rotw 2 -40000cc1: fdb056 bnez a0, 40000ca0 <_Level5FromVector+0x38> -40000cc4: 408020 rotw 2 -40000cc7: 034930 rsr.windowstart a3 -40000cca: 034840 rsr.windowbase a4 -40000ccd: 1239 s32i.n a3, a2, 4 -40000ccf: 2249 s32i.n a4, a2, 8 -40000cd1: 130c movi.n a3, 1 -40000cd3: 040c movi.n a4, 0 -40000cd5: 134930 wsr.windowstart a3 -40000cd8: 134840 wsr.windowbase a4 -40000cdb: 002010 rsync -40000cde: fe3a11 l32r a1, 400005c8 <_stext+0x68> -40000ce1: 000c movi.n a0, 0 -40000ce3: fe3b21 l32r a2, 400005d0 <_stext+0x70> -40000ce6: 13e620 wsr.ps a2 -40000ce9: 002010 rsync -40000cec: 0303e0 rsr.sar a14 -40000cef: 01e9 s32i.n a14, a1, 0 -40000cf1: 0302e0 rsr.lcount a14 -40000cf4: a1e9 s32i.n a14, a1, 40 -40000cf6: 0300e0 rsr.lbeg a14 -40000cf9: b1e9 s32i.n a14, a1, 44 -40000cfb: 0301e0 rsr.lend a14 -40000cfe: c1e9 s32i.n a14, a1, 48 -40000d00: 0310e0 rsr.acclo a14 -40000d03: 81e9 s32i.n a14, a1, 32 -40000d05: 0311e0 rsr.acchi a14 -40000d08: 91e9 s32i.n a14, a1, 36 -40000d0a: 03e2f0 rsr.interrupt a15 -40000d0d: 03e4c0 rsr.intenable a12 -40000d10: fe31d1 l32r a13, 400005d4 <_stext+0x74> -40000d13: 10ffc0 and a15, a15, a12 -40000d16: 10ffd0 and a15, a15, a13 -40000d19: 02af16 beqz a15, 40000d47 <_Level5FromVector+0xdf> -40000d1c: 60e0f0 neg a14, a15 -40000d1f: 10eef0 and a14, a14, a15 -40000d22: 13e3e0 wsr.intclear a14 -40000d25: fe1ec1 l32r a12, 400005a0 <_stext+0x40> -40000d28: 40fee0 nsau a14, a14 -40000d2b: b0cec0 addx8 a12, a14, a12 -40000d2e: 0cd8 l32i.n a13, a12, 0 -40000d30: 1c68 l32i.n a6, a12, 4 -40000d32: 000dd0 callx4 a13 -40000d35: 03e2f0 rsr.interrupt a15 -40000d38: 03e4c0 rsr.intenable a12 -40000d3b: fe26d1 l32r a13, 400005d4 <_stext+0x74> -40000d3e: 10ffc0 and a15, a15, a12 -40000d41: 10ffd0 and a15, a15, a13 -40000d44: fd4f56 bnez a15, 40000d1c <_Level5FromVector+0xb4> -40000d47: a1d8 l32i.n a13, a1, 40 -40000d49: b1e8 l32i.n a14, a1, 44 -40000d4b: c1f8 l32i.n a15, a1, 48 -40000d4d: 1302d0 wsr.lcount a13 -40000d50: 1300e0 wsr.lbeg a14 -40000d53: 1301f0 wsr.lend a15 -40000d56: 81d8 l32i.n a13, a1, 32 -40000d58: 91e8 l32i.n a14, a1, 36 -40000d5a: 1310d0 wsr.acclo a13 -40000d5d: 1311e0 wsr.acchi a14 -40000d60: 01f8 l32i.n a15, a1, 0 -40000d62: 1303f0 wsr.sar a15 -40000d65: 523c movi.n a2, 53 -40000d67: 13e620 wsr.ps a2 -40000d6a: 002010 rsync -40000d6d: 1128 l32i.n a2, a1, 4 -40000d6f: 022132 l32i a3, a1, 8 -40000d72: 134920 wsr.windowstart a2 -40000d75: 134830 wsr.windowbase a3 -40000d78: 002010 rsync -40000d7b: fe1311 l32r a1, 400005c8 <_stext+0x68> -40000d7e: 38a062 movi a6, 56 -40000d81: e0c172 addi a7, a1, -32 -40000d84: f8c6e2 addi a14, a6, -8 -40000d87: 20c7f2 addi a15, a7, 32 -40000d8a: 112f42 l32i a4, a15, 68 -40000d8d: 122f52 l32i a5, a15, 72 -40000d90: 132f62 l32i a6, a15, 76 -40000d93: 142f72 l32i a7, a15, 80 -40000d96: 152f82 l32i a8, a15, 84 -40000d99: 162f92 l32i a9, a15, 88 -40000d9c: 172fa2 l32i a10, a15, 92 -40000d9f: 182fb2 l32i a11, a15, 96 -40000da2: 408020 rotw 2 -40000da5: fdb656 bnez a6, 40000d84 <_Level5FromVector+0x11c> -40000da8: 192742 l32i a4, a7, 100 -40000dab: 1a2752 l32i a5, a7, 104 -40000dae: 1b2762 l32i a6, a7, 108 -40000db1: 1c2772 l32i a7, a7, 112 -40000db4: 408020 rotw 2 -40000db7: 3128 l32i.n a2, a1, 12 -40000db9: 4138 l32i.n a3, a1, 16 -40000dbb: 13b120 wsr.epc1 a2 -40000dbe: 13e830 wsr.exccause a3 -40000dc1: 5128 l32i.n a2, a1, 20 -40000dc3: 13ee20 wsr.excvaddr a2 -40000dc6: 6138 l32i.n a3, a1, 24 -40000dc8: 13d130 wsr.excsave1 a3 -40000dcb: d108 l32i.n a0, a1, 52 -40000dcd: f128 l32i.n a2, a1, 60 -40000dcf: 102132 l32i a3, a1, 64 -40000dd2: e118 l32i.n a1, a1, 56 -40000dd4: 003510 rfi 5 - ... - -40000dd8 <_xtos_cause3_handler>: -40000dd8: 320c movi.n a2, 3 -40000dda: 000286 j 40000de8 <_xtos_c_wrapper_handler> -40000ddd: 000000 ill -40000de0: fdc332 addi a3, a3, -3 -40000de3: 332a add.n a3, a3, a2 -40000de5: 000446 j 40000dfa <_xtos_c_wrapper_handler+0x12> - -40000de8 <_xtos_c_wrapper_handler>: -40000de8: 7159 s32i.n a5, a1, 28 -40000dea: 8129 s32i.n a2, a1, 32 -40000dec: 03e620 rsr.ps a2 -40000def: fde631 l32r a3, 40000588 <_stext+0x28> -40000df2: 1129 s32i.n a2, a1, 4 -40000df4: 342020 extui a2, a2, 0, 4 -40000df7: e542f6 bgeui a2, 4, 40000de0 <_xtos_cause3_handler+0x8> -40000dfa: 03b120 rsr.epc1 a2 -40000dfd: 13e630 wsr.ps a3 -40000e00: 0129 s32i.n a2, a1, 0 -40000e02: 3b2122 l32i a2, a1, 236 -40000e05: 01d112 addmi a1, a1, 0x100 -40000e08: 002010 rsync -40000e0b: fde241 l32r a4, 40000594 <_stext+0x34> -40000e0e: 203430 or a3, a4, a3 -40000e11: 904430 addx2 a4, a4, a3 - -40000e14 <_GeneralException>: -40000e14: 020136 entry a1, 0x100 -40000e17: 0303c0 rsr.sar a12 -40000e1a: 11d8 l32i.n a13, a1, 4 -40000e1c: 03e6e0 rsr.ps a14 -40000e1f: 34d0d0 extui a13, a13, 0, 4 -40000e22: 34f0e0 extui a15, a14, 0, 4 -40000e25: 30eef0 xor a14, a14, a15 -40000e28: 30eed0 xor a14, a14, a13 -40000e2b: 13e6e0 wsr.ps a14 -40000e2e: fdd4d1 l32r a13, 40000580 <_stext+0x20> -40000e31: 81f8 l32i.n a15, a1, 32 -40000e33: 21c9 s32i.n a12, a1, 8 -40000e35: 0302c0 rsr.lcount a12 -40000e38: 0300e0 rsr.lbeg a14 -40000e3b: 91c9 s32i.n a12, a1, 36 -40000e3d: 0301c0 rsr.lend a12 -40000e40: a1e9 s32i.n a14, a1, 40 -40000e42: b1c9 s32i.n a12, a1, 44 -40000e44: 0310c0 rsr.acclo a12 -40000e47: 0311e0 rsr.acchi a14 -40000e4a: c1c9 s32i.n a12, a1, 48 -40000e4c: d1e9 s32i.n a14, a1, 52 -40000e4e: a0cfd0 addx4 a12, a15, a13 -40000e51: 0cc8 l32i.n a12, a12, 0 -40000e53: 01ed mov.n a14, a1 -40000e55: 1c8c beqz.n a12, 40000e5a <_GeneralException+0x46> -40000e57: 000cf0 callx12 a12 -40000e5a: 91d8 l32i.n a13, a1, 36 -40000e5c: a1e8 l32i.n a14, a1, 40 -40000e5e: b1f8 l32i.n a15, a1, 44 -40000e60: 1302d0 wsr.lcount a13 -40000e63: 1300e0 wsr.lbeg a14 -40000e66: 1301f0 wsr.lend a15 -40000e69: c1d8 l32i.n a13, a1, 48 -40000e6b: d1e8 l32i.n a14, a1, 52 -40000e6d: 1310d0 wsr.acclo a13 -40000e70: 1311e0 wsr.acchi a14 -40000e73: 21e8 l32i.n a14, a1, 8 -40000e75: 0063c0 rsil a12, 3 -40000e78: 1303e0 wsr.sar a14 -40000e7b: fdca01 l32r a0, 400005a4 <_stext+0x44> -40000e7e: fdc5d1 l32r a13, 40000594 <_stext+0x34> -40000e81: 2000d0 or a0, a0, a13 -40000e84: 900d00 addx2 a0, a13, a0 -40000e87: f01d retw.n -40000e89: 000000 ill - -40000e8c : -40000e8c: 004136 entry a1, 32 -40000e8f: 20a220 or a10, a2, a2 -40000e92: 01a6b2 movi a11, 0x601 -40000e95: 20c330 or a12, a3, a3 -40000e98: 008f25 call8 4000178c -40000e9b: 202aa0 or a2, a10, a10 -40000e9e: f01d retw.n - -40000ea0 <_isatty_r>: -40000ea0: 00c136 entry a1, 96 -40000ea3: 02ad mov.n a10, a2 -40000ea5: 03bd mov.n a11, a3 -40000ea7: 01cd mov.n a12, a1 -40000ea9: 0ae225 call8 4000bccc <_fstat_r> -40000eac: 014a96 bltz a10, 40000ec4 <_isatty_r+0x24> -40000eaf: fdca21 l32r a2, 400005d8 <_stext+0x78> -40000eb2: 1198 l32i.n a9, a1, 4 -40000eb4: 180c movi.n a8, 1 -40000eb6: 109920 and a9, a9, a2 -40000eb9: e0d992 addmi a9, a9, 0xffffe000 -40000ebc: 020c movi.n a2, 0 -40000ebe: 832890 moveqz a2, a8, a9 -40000ec1: f01d retw.n -40000ec3: 020c00 andb b0, b12, b0 -40000ec6: f01d retw.n - -40000ec8 : -40000ec8: 006136 entry a1, 48 -40000ecb: 028d mov.n a8, a2 -40000ecd: 1898 l32i.n a9, a8, 4 -40000ecf: 68c8 l32i.n a12, a8, 24 -40000ed1: 48d8 l32i.n a13, a8, 16 -40000ed3: 0199 s32i.n a9, a1, 0 -40000ed5: 0898 l32i.n a9, a8, 0 -40000ed7: 6ca7a2 movi a10, 0x76c -40000eda: 1199 s32i.n a9, a1, 4 -40000edc: 5898 l32i.n a9, a8, 20 -40000ede: 90ccc0 addx2 a12, a12, a12 -40000ee1: 9a9a add.n a9, a10, a9 -40000ee3: 2199 s32i.n a9, a1, 8 -40000ee5: fdbe91 l32r a9, 400005e0 <_stext+0x80> -40000ee8: 90ddd0 addx2 a13, a13, a13 -40000eeb: c9ca add.n a12, a9, a12 -40000eed: fdbd91 l32r a9, 400005e4 <_stext+0x84> -40000ef0: fdbbb1 l32r a11, 400005dc <_stext+0x7c> -40000ef3: 38e8 l32i.n a14, a8, 12 -40000ef5: 28f8 l32i.n a15, a8, 8 -40000ef7: 03ad mov.n a10, a3 -40000ef9: d9da add.n a13, a9, a13 -40000efb: 032d mov.n a2, a3 -40000efd: 55d0a5 call8 40056c08 -40000f00: f01d retw.n - ... - -40000f04 : -40000f04: 004136 entry a1, 32 -40000f07: fdb881 l32r a8, 400005e8 <_stext+0x88> -40000f0a: 0888 l32i.n a8, a8, 0 -40000f0c: 282a add.n a2, a8, a2 -40000f0e: 010222 l8ui a2, a2, 1 -40000f11: 242020 extui a2, a2, 0, 3 -40000f14: f01d retw.n - ... - -40000f18 : -40000f18: 004136 entry a1, 32 -40000f1b: fdb381 l32r a8, 400005e8 <_stext+0x88> -40000f1e: 0888 l32i.n a8, a8, 0 -40000f20: 282a add.n a2, a8, a2 -40000f22: 010222 l8ui a2, a2, 1 -40000f25: 142020 extui a2, a2, 0, 2 -40000f28: f01d retw.n - ... - -40000f2c : -40000f2c: 004136 entry a1, 32 -40000f2f: fdae81 l32r a8, 400005e8 <_stext+0x88> -40000f32: 0888 l32i.n a8, a8, 0 -40000f34: 882a add.n a8, a8, a2 -40000f36: 010892 l8ui a9, a8, 1 -40000f39: 180c movi.n a8, 1 -40000f3b: 239900 sext a9, a9, 7 -40000f3e: 00a996 bltz a9, 40000f4c -40000f41: f7c292 addi a9, a2, -9 -40000f44: 020c movi.n a2, 0 -40000f46: 832890 moveqz a2, a8, a9 -40000f49: f01d retw.n -40000f4b: 082d00 lsx f2, a13, a0 -40000f4e: f01d retw.n - -40000f50 : -40000f50: 004136 entry a1, 32 -40000f53: fda581 l32r a8, 400005e8 <_stext+0x88> -40000f56: 0888 l32i.n a8, a8, 0 -40000f58: 282a add.n a2, a8, a2 -40000f5a: 010222 l8ui a2, a2, 1 -40000f5d: 082c movi.n a8, 32 -40000f5f: 102280 and a2, a2, a8 -40000f62: f01d retw.n - -40000f64 : -40000f64: 004136 entry a1, 32 -40000f67: fda081 l32r a8, 400005e8 <_stext+0x88> -40000f6a: 0888 l32i.n a8, a8, 0 -40000f6c: 282a add.n a2, a8, a2 -40000f6e: 010222 l8ui a2, a2, 1 -40000f71: 480c movi.n a8, 4 -40000f73: 102280 and a2, a2, a8 -40000f76: f01d retw.n - -40000f78 : -40000f78: 004136 entry a1, 32 -40000f7b: fd9b81 l32r a8, 400005e8 <_stext+0x88> -40000f7e: 0888 l32i.n a8, a8, 0 -40000f80: 282a add.n a2, a8, a2 -40000f82: 010292 l8ui a9, a2, 1 -40000f85: 180c movi.n a8, 1 -40000f87: 149090 extui a9, a9, 0, 2 -40000f8a: fec992 addi a9, a9, -2 -40000f8d: 020c movi.n a2, 0 -40000f8f: 832890 moveqz a2, a8, a9 -40000f92: f01d retw.n - -40000f94 : -40000f94: 004136 entry a1, 32 -40000f97: fd9481 l32r a8, 400005e8 <_stext+0x88> -40000f9a: 0888 l32i.n a8, a8, 0 -40000f9c: 282a add.n a2, a8, a2 -40000f9e: 010282 l8ui a8, a2, 1 -40000fa1: 721c movi.n a2, 23 -40000fa3: 102280 and a2, a2, a8 -40000fa6: f01d retw.n - -40000fa8 : -40000fa8: 004136 entry a1, 32 -40000fab: fd8f81 l32r a8, 400005e8 <_stext+0x88> -40000fae: 0888 l32i.n a8, a8, 0 -40000fb0: 282a add.n a2, a8, a2 -40000fb2: 010282 l8ui a8, a2, 1 -40000fb5: 97a022 movi a2, 151 -40000fb8: 102280 and a2, a2, a8 -40000fbb: f01d retw.n -40000fbd: 000000 ill - -40000fc0 : -40000fc0: 004136 entry a1, 32 -40000fc3: fd8981 l32r a8, 400005e8 <_stext+0x88> -40000fc6: 0888 l32i.n a8, a8, 0 -40000fc8: 282a add.n a2, a8, a2 -40000fca: 010222 l8ui a2, a2, 1 -40000fcd: 081c movi.n a8, 16 -40000fcf: 102280 and a2, a2, a8 -40000fd2: f01d retw.n - -40000fd4 : -40000fd4: 004136 entry a1, 32 -40000fd7: fd8481 l32r a8, 400005e8 <_stext+0x88> -40000fda: 0888 l32i.n a8, a8, 0 -40000fdc: 282a add.n a2, a8, a2 -40000fde: 010222 l8ui a2, a2, 1 -40000fe1: 880c movi.n a8, 8 -40000fe3: 102280 and a2, a2, a8 -40000fe6: f01d retw.n - -40000fe8 : -40000fe8: 004136 entry a1, 32 -40000feb: fd7f81 l32r a8, 400005e8 <_stext+0x88> -40000fee: 0888 l32i.n a8, a8, 0 -40000ff0: 282a add.n a2, a8, a2 -40000ff2: 010292 l8ui a9, a2, 1 -40000ff5: 180c movi.n a8, 1 -40000ff7: 149090 extui a9, a9, 0, 2 -40000ffa: 990b addi.n a9, a9, -1 -40000ffc: 020c movi.n a2, 0 -40000ffe: 832890 moveqz a2, a8, a9 -40001001: f01d retw.n - ... - -40001004 : -40001004: 004136 entry a1, 32 -40001007: 0ae865 call8 4000be8c <__getreent> -4000100a: 0e2a82 l32i a8, a10, 56 -4000100d: 203aa0 or a3, a10, a10 -40001010: 88fc bnez.n a8, 4000104c -40001012: 18a0a2 movi a10, 24 -40001015: 0ae8a5 call8 4000bea0 -40001018: fd7541 l32r a4, 400005ec <_stext+0x8c> -4000101b: e3a9 s32i.n a10, a3, 56 -4000101d: 005a42 s16i a4, a10, 0 -40001020: fd7441 l32r a4, 400005f0 <_stext+0x90> -40001023: 580c movi.n a8, 5 -40001025: 015a42 s16i a4, a10, 2 -40001028: fd7341 l32r a4, 400005f4 <_stext+0x94> -4000102b: 055a82 s16i a8, a10, 10 -4000102e: 025a42 s16i a4, a10, 4 -40001031: fd7141 l32r a4, 400005f8 <_stext+0x98> -40001034: b80c movi.n a8, 11 -40001036: 035a42 s16i a4, a10, 6 -40001039: 065a82 s16i a8, a10, 12 -4000103c: fd7041 l32r a4, 400005fc <_stext+0x9c> -4000103f: fd7081 l32r a8, 40000600 <_stext+0xa0> -40001042: fd7091 l32r a9, 40000604 <_stext+0xa4> -40001045: 045a42 s16i a4, a10, 8 -40001048: 4a89 s32i.n a8, a10, 16 -4000104a: 5a99 s32i.n a9, a10, 20 -4000104c: e338 l32i.n a3, a3, 56 -4000104e: 4329 s32i.n a2, a3, 16 -40001050: 020c movi.n a2, 0 -40001052: 5329 s32i.n a2, a3, 20 -40001054: f01d retw.n - ... - -40001058 : -40001058: 004136 entry a1, 32 -4000105b: 0ae325 call8 4000be8c <__getreent> -4000105e: 0e2a82 l32i a8, a10, 56 -40001061: 202aa0 or a2, a10, a10 -40001064: 88fc bnez.n a8, 400010a0 -40001066: 18a0a2 movi a10, 24 -40001069: 0ae365 call8 4000bea0 -4000106c: fd6031 l32r a3, 400005ec <_stext+0x8c> -4000106f: e2a9 s32i.n a10, a2, 56 -40001071: 005a32 s16i a3, a10, 0 -40001074: fd5f31 l32r a3, 400005f0 <_stext+0x90> -40001077: 580c movi.n a8, 5 -40001079: 015a32 s16i a3, a10, 2 -4000107c: fd5e31 l32r a3, 400005f4 <_stext+0x94> -4000107f: 055a82 s16i a8, a10, 10 -40001082: 025a32 s16i a3, a10, 4 -40001085: fd5c31 l32r a3, 400005f8 <_stext+0x98> -40001088: b80c movi.n a8, 11 -4000108a: 035a32 s16i a3, a10, 6 -4000108d: 065a82 s16i a8, a10, 12 -40001090: fd5b31 l32r a3, 400005fc <_stext+0x9c> -40001093: fd5b81 l32r a8, 40000600 <_stext+0xa0> -40001096: fd5b91 l32r a9, 40000604 <_stext+0xa4> -40001099: 045a32 s16i a3, a10, 8 -4000109c: 4a89 s32i.n a8, a10, 16 -4000109e: 5a99 s32i.n a9, a10, 20 -400010a0: e288 l32i.n a8, a2, 56 -400010a2: fd5aa1 l32r a10, 4000060c <_stext+0xac> -400010a5: 4898 l32i.n a9, a8, 16 -400010a7: fd5821 l32r a2, 40000608 <_stext+0xa8> -400010aa: 58b8 l32i.n a11, a8, 20 -400010ac: 82a9a0 mull a10, a9, a10 -400010af: 82bb20 mull a11, a11, a2 -400010b2: abaa add.n a10, a11, a10 -400010b4: 82b920 mull a11, a9, a2 -400010b7: a22920 muluh a2, a9, a2 -400010ba: 9b1b addi.n a9, a11, 1 -400010bc: 2a2a add.n a2, a10, a2 -400010be: 1a0c movi.n a10, 1 -400010c0: 0139b7 bltu a9, a11, 400010c5 -400010c3: 0a0c movi.n a10, 0 -400010c5: 2a2a add.n a2, a10, a2 -400010c7: 5829 s32i.n a2, a8, 20 -400010c9: 4899 s32i.n a9, a8, 16 -400010cb: fd5181 l32r a8, 40000610 <_stext+0xb0> -400010ce: 102280 and a2, a2, a8 -400010d1: f01d retw.n - ... - -400010d4 : -400010d4: 004136 entry a1, 32 -400010d7: 0288 l32i.n a8, a2, 0 -400010d9: fd4e91 l32r a9, 40000614 <_stext+0xb4> -400010dc: 838980 moveqz a8, a9, a8 -400010df: fd4e91 l32r a9, 40000618 <_stext+0xb8> -400010e2: 31af80 srai a10, a8, 31 -400010e5: b29890 mulsh a9, a8, a9 -400010e8: 989a add.n a9, a8, a9 -400010ea: 319090 srai a9, a9, 16 -400010ed: c099a0 sub a9, a9, a10 -400010f0: fd4ba1 l32r a10, 4000061c <_stext+0xbc> -400010f3: 82a9a0 mull a10, a9, a10 -400010f6: 88aa add.n a8, a8, a10 -400010f8: fd4aa1 l32r a10, 40000620 <_stext+0xc0> -400010fb: 8288a0 mull a8, a8, a10 -400010fe: fd49a1 l32r a10, 40000624 <_stext+0xc4> -40001101: 8299a0 mull a9, a9, a10 -40001104: 889a add.n a8, a8, a9 -40001106: fd4291 l32r a9, 40000610 <_stext+0xb0> -40001109: a89a add.n a10, a8, a9 -4000110b: a38a80 movltz a8, a10, a8 -4000110e: 0289 s32i.n a8, a2, 0 -40001110: 102890 and a2, a8, a9 -40001113: f01d retw.n -40001115: 000000 ill - -40001118 <__sread>: -40001118: 004136 entry a1, 32 -4000111b: 0793b2 l16si a11, a3, 14 -4000111e: 02ad mov.n a10, a2 -40001120: 04cd mov.n a12, a4 -40001122: 20d550 or a13, a5, a5 -40001125: 0ac825 call8 4000bda8 <_read_r> -40001128: 00ca96 bltz a10, 40001138 <__sread+0x20> -4000112b: 152382 l32i a8, a3, 84 -4000112e: 88aa add.n a8, a8, a10 -40001130: 156382 s32i a8, a3, 84 -40001133: 000346 j 40001144 <__sread+0x2c> -40001136: 920000 lsi f0, a0, 0x248 -40001139: 810613 lsi f1, a6, 0x204 -4000113c: fd3b addi.n a15, a13, 3 -4000113e: 108980 and a8, a9, a8 -40001141: 065382 s16i a8, a3, 12 -40001144: 0a2d mov.n a2, a10 -40001146: f01d retw.n - -40001148 <__seofread>: -40001148: 004136 entry a1, 32 -4000114b: 020c movi.n a2, 0 -4000114d: f01d retw.n - ... - -40001150 <__swrite>: -40001150: 004136 entry a1, 32 -40001153: 061382 l16ui a8, a3, 12 -40001156: 0b6887 bbci a8, 8, 40001165 <__swrite+0x15> -40001159: 0793b2 l16si a11, a3, 14 -4000115c: 02ad mov.n a10, a2 -4000115e: 0c0c movi.n a12, 0 -40001160: 2d0c movi.n a13, 2 -40001162: 0ac2a5 call8 4000bd8c <_lseek_r> -40001165: 061392 l16ui a9, a3, 12 -40001168: fd3081 l32r a8, 40000628 <_stext+0xc8> -4000116b: 0793b2 l16si a11, a3, 14 -4000116e: 108980 and a8, a9, a8 -40001171: 065382 s16i a8, a3, 12 -40001174: 20a220 or a10, a2, a2 -40001177: 20c440 or a12, a4, a4 -4000117a: 20d550 or a13, a5, a5 -4000117d: 0abf25 call8 4000bd70 <_write_r> -40001180: 0a2d mov.n a2, a10 -40001182: f01d retw.n - -40001184 <__sseek>: -40001184: 004136 entry a1, 32 -40001187: 0793b2 l16si a11, a3, 14 -4000118a: 02ad mov.n a10, a2 -4000118c: 04cd mov.n a12, a4 -4000118e: 20d550 or a13, a5, a5 -40001191: 0abfa5 call8 4000bd8c <_lseek_r> -40001194: 061382 l16ui a8, a3, 12 -40001197: 0d0a66 bnei a10, -1, 400011a8 <__sseek+0x24> -4000119a: fd2391 l32r a9, 40000628 <_stext+0xc8> -4000119d: 108980 and a8, a9, a8 -400011a0: 065382 s16i a8, a3, 12 -400011a3: 000346 j 400011b4 <__sseek+0x30> -400011a6: 910000 srl a0, a0 -400011a9: a2fd21 l32r a2, 3ffe9da0 <__stack_app+0x1f70> -400011ac: 801563 lsi f6, a5, 0x200 -400011af: 2089 s32i.n a8, a0, 8 -400011b1: 065382 s16i a8, a3, 12 -400011b4: 0a2d mov.n a2, a10 -400011b6: f01d retw.n - -400011b8 <__sclose>: -400011b8: 004136 entry a1, 32 -400011bb: 0793b2 l16si a11, a3, 14 -400011be: 20a220 or a10, a2, a2 -400011c1: 0ab7a5 call8 4000bd3c <_close_r> -400011c4: 202aa0 or a2, a10, a10 -400011c7: 000090 retw - ... - -400011cc : -400011cc: 004136 entry a1, 32 -400011cf: 02cd mov.n a12, a2 -400011d1: fd0521 l32r a2, 400005e8 <_stext+0x88> -400011d4: 080c movi.n a8, 0 -400011d6: 02b8 l32i.n a11, a2, 0 -400011d8: 2c8a add.n a2, a12, a8 -400011da: 000292 l8ui a9, a2, 0 -400011dd: 2b9a add.n a2, a11, a9 -400011df: 010222 l8ui a2, a2, 1 -400011e2: 20c9a2 addi a10, a9, 32 -400011e5: 142020 extui a2, a2, 0, 2 -400011e8: 220b addi.n a2, a2, -1 -400011ea: 839a20 moveqz a9, a10, a2 -400011ed: 092d mov.n a2, a9 -400011ef: 938a add.n a9, a3, a8 -400011f1: 000992 l8ui a9, a9, 0 -400011f4: ab9a add.n a10, a11, a9 -400011f6: 010aa2 l8ui a10, a10, 1 -400011f9: 20c9d2 addi a13, a9, 32 -400011fc: 14a0a0 extui a10, a10, 0, 2 -400011ff: aa0b addi.n a10, a10, -1 -40001201: 839da0 moveqz a9, a13, a10 -40001204: c02290 sub a2, a2, a9 -40001207: 32cc bnez.n a2, 4000120e -40001209: 881b addi.n a8, a8, 1 -4000120b: fc9956 bnez a9, 400011d8 -4000120e: f01d retw.n - -40001210 : -40001210: 006136 entry a1, 48 -40001213: 000382 l8ui a8, a3, 0 -40001216: 024d mov.n a4, a2 -40001218: 055816 beqz a8, 40001271 -4000121b: fcf321 l32r a2, 400005e8 <_stext+0x88> -4000121e: 331b addi.n a3, a3, 1 -40001220: 0228 l32i.n a2, a2, 0 -40001222: 03ad mov.n a10, a3 -40001224: 0129 s32i.n a2, a1, 0 -40001226: 228a add.n a2, a2, a8 -40001228: 010272 l8ui a7, a2, 1 -4000122b: 20c822 addi a2, a8, 32 -4000122e: 147070 extui a7, a7, 0, 2 -40001231: 770b addi.n a7, a7, -1 -40001233: 838270 moveqz a8, a2, a7 -40001236: 747080 extui a7, a8, 0, 8 -40001239: 002865 call8 400014c0 -4000123c: 0a5d mov.n a5, a10 -4000123e: 000046 j 40001243 -40001241: 064d mov.n a4, a6 -40001243: 000422 l8ui a2, a4, 0 -40001246: 641b addi.n a6, a4, 1 -40001248: 52ac beqz.n a2, 40001271 -4000124a: 0188 l32i.n a8, a1, 0 -4000124c: 982a add.n a9, a8, a2 -4000124e: 0109a2 l8ui a10, a9, 1 -40001251: 20c292 addi a9, a2, 32 -40001254: 14a0a0 extui a10, a10, 0, 2 -40001257: aa0b addi.n a10, a10, -1 -40001259: 8329a0 moveqz a2, a9, a10 -4000125c: 742020 extui a2, a2, 0, 8 -4000125f: de9277 bne a2, a7, 40001241 -40001262: 06ad mov.n a10, a6 -40001264: 03bd mov.n a11, a3 -40001266: 20c550 or a12, a5, a5 -40001269: 002e65 call8 40001550 -4000126c: fd1a56 bnez a10, 40001241 -4000126f: 042d mov.n a2, a4 -40001271: f01d retw.n - ... - -40001274 : -40001274: 002136 entry a1, 16 -40001277: 000282 l8ui a8, a2, 0 -4000127a: 000392 l8ui a9, a3, 0 -4000127d: 3a0c movi.n a10, 3 -4000127f: 529897 bne a8, a9, 400012d5 -40001282: 20b230 or a11, a2, a3 -40001285: 530ba7 bnone a11, a10, 400012dc -40001288: 30b230 xor a11, a2, a3 -4000128b: 318ba7 bany a11, a10, 400012c0 -4000128e: 221b addi.n a2, a2, 1 -40001290: 0b2816 beqz a8, 40001346 -40001293: 331b addi.n a3, a3, 1 -40001295: 4302a7 bnone a2, a10, 400012dc -40001298: 000282 l8ui a8, a2, 0 -4000129b: 000392 l8ui a9, a3, 0 -4000129e: 221b addi.n a2, a2, 1 -400012a0: 319897 bne a8, a9, 400012d5 -400012a3: 09f816 beqz a8, 40001346 -400012a6: 331b addi.n a3, a3, 1 -400012a8: 3002a7 bnone a2, a10, 400012dc -400012ab: 000282 l8ui a8, a2, 0 -400012ae: 000392 l8ui a9, a3, 0 -400012b1: 221b addi.n a2, a2, 1 -400012b3: 1e9897 bne a8, a9, 400012d5 -400012b6: 08c816 beqz a8, 40001346 -400012b9: 331b addi.n a3, a3, 1 -400012bb: 000746 j 400012dc -400012be: 0c0000 lsi f0, a0, 48 -400012c1: 7608 l32i.n a0, a6, 28 -400012c3: 0f88 l32i.n a8, a15, 0 -400012c5: 000282 l8ui a8, a2, 0 -400012c8: 000392 l8ui a9, a3, 0 -400012cb: 221b addi.n a2, a2, 1 -400012cd: 049897 bne a8, a9, 400012d5 -400012d0: 331b addi.n a3, a3, 1 -400012d2: fff816 beqz a8, 400012d5 -400012d5: c02890 sub a2, a8, a9 -400012d8: f01d retw.n -400012da: 410000 srli a0, a0, 0 -400012dd: 71fcd5 call4 400732ac <__bss_start+0x32ac> -400012e0: fcd8 l32i.n a13, a12, 60 -400012e2: 238076 loop a0, 40001309 -400012e5: 0288 l32i.n a8, a2, 0 -400012e7: 0398 l32i.n a9, a3, 0 -400012e9: 1158f0 slli a5, a8, 1 -400012ec: 5c9897 bne a8, a9, 4000134c -400012ef: 209850 or a9, a8, a5 -400012f2: 1ac977 bnall a9, a7, 40001310 -400012f5: 1288 l32i.n a8, a2, 4 -400012f7: 1398 l32i.n a9, a3, 4 -400012f9: 1158f0 slli a5, a8, 1 -400012fc: 4c9897 bne a8, a9, 4000134c -400012ff: 209850 or a9, a8, a5 -40001302: 06c977 bnall a9, a7, 4000130c -40001305: 228b addi.n a2, a2, 8 -40001307: 338b addi.n a3, a3, 8 -40001309: fff546 j 400012e2 -4000130c: 224b addi.n a2, a2, 4 -4000130e: 334b addi.n a3, a3, 4 -40001310: 320847 bnone a8, a4, 40001346 -40001313: fcc851 l32r a5, 40000634 <_stext+0xd4> -40001316: fcc861 l32r a6, 40000638 <_stext+0xd8> -40001319: 290857 bnone a8, a5, 40001346 -4000131c: fcc871 l32r a7, 4000063c <_stext+0xdc> -4000131f: 230867 bnone a8, a6, 40001346 -40001322: 200877 bnone a8, a7, 40001346 -40001325: 224b addi.n a2, a2, 4 -40001327: 334b addi.n a3, a3, 4 -40001329: 198076 loop a0, 40001346 -4000132c: 0288 l32i.n a8, a2, 0 -4000132e: 0398 l32i.n a9, a3, 0 -40001330: 224b addi.n a2, a2, 4 -40001332: 169897 bne a8, a9, 4000134c -40001335: 0d0847 bnone a8, a4, 40001346 -40001338: 0a0857 bnone a8, a5, 40001346 -4000133b: 070867 bnone a8, a6, 40001346 -4000133e: 040877 bnone a8, a7, 40001346 -40001341: 334b addi.n a3, a3, 4 -40001343: fff886 j 40001329 -40001346: 020c movi.n a2, 0 -40001348: f01d retw.n -4000134a: 900000 addx2 a0, a0, a0 -4000134d: 3028 l32i.n a2, a0, 12 -4000134f: 218247 bany a2, a4, 40001374 -40001352: fcb851 l32r a5, 40000634 <_stext+0xd4> -40001355: ed0847 bnone a8, a4, 40001346 -40001358: 248257 bany a2, a5, 40001380 -4000135b: fcb761 l32r a6, 40000638 <_stext+0xd8> -4000135e: e40857 bnone a8, a5, 40001346 -40001361: 278267 bany a2, a6, 4000138c -40001364: de0867 bnone a8, a6, 40001346 -40001367: 75a880 extui a10, a8, 24, 8 -4000136a: 75b890 extui a11, a9, 24, 8 -4000136d: c02ab0 sub a2, a10, a11 -40001370: f01d retw.n -40001372: 800000 add a0, a0, a0 -40001375: 9074a0 addx2 a7, a4, a10 -40001378: b074b0 addx8 a7, a4, a11 -4000137b: c02a add.n a12, a0, a2 -4000137d: f01d retw.n -4000137f: a88000 lsi f0, a0, 0x2a0 -40001382: b89074 lsi f7, a0, 0x2e0 -40001385: 2ab074 lsi f7, a0, 168 -40001388: f01dc0 subx8 a1, a13, a12 -4000138b: a08000 addx4 a8, a0, a0 -4000138e: b09075 call12 3ffb1c94 <_data_end_btdm+0x1d84> -40001391: 2ab075 call12 4002be98 -40001394: f01dc0 subx8 a1, a13, a12 - ... - -40001398 : -40001398: 004136 entry a1, 32 -4000139b: 20a220 or a10, a2, a2 -4000139e: 20b330 or a11, a3, a3 -400013a1: ffed25 call8 40001274 -400013a4: 202aa0 or a2, a10, a10 -400013a7: f01d retw.n -400013a9: 000000 ill - -400013ac : -400013ac: 002136 entry a1, 16 -400013af: 20a220 or a10, a2, a2 -400013b2: ffa042 movi a4, 255 -400013b5: fc9f51 l32r a5, 40000634 <_stext+0xd4> -400013b8: fca061 l32r a6, 40000638 <_stext+0xd8> -400013bb: fca071 l32r a7, 4000063c <_stext+0xdc> -400013be: 0be307 bbsi a3, 0, 400013cd -400013c1: 17e317 bbsi a3, 1, 400013dc -400013c4: 380c movi.n a8, 3 -400013c6: 2a0a87 bnone a10, a8, 400013f4 -400013c9: 0016c6 j 40001428 -400013cc: 038200 lsi f0, a2, 12 -400013cf: 331b00 clamps a1, a11, 7 -400013d2: 004a82 s8i a8, a10, 0 -400013d5: 889c beqz.n a8, 400013f1 -400013d7: aa1b addi.n a10, a10, 1 -400013d9: e76317 bbci a3, 1, 400013c4 -400013dc: 000382 l8ui a8, a3, 0 -400013df: 004a82 s8i a8, a10, 0 -400013e2: b88c beqz.n a8, 400013f1 -400013e4: 010382 l8ui a8, a3, 1 -400013e7: 332b addi.n a3, a3, 2 -400013e9: 014a82 s8i a8, a10, 1 -400013ec: aa2b addi.n a10, a10, 2 -400013ee: fd2856 bnez a8, 400013c4 -400013f1: f01d retw.n -400013f3: 080c00 lsx f0, a12, a0 -400013f6: 138876 loop a8, 4000140d -400013f9: 0388 l32i.n a8, a3, 0 -400013fb: 334b addi.n a3, a3, 4 -400013fd: 0f0847 bnone a8, a4, 40001410 -40001400: 110857 bnone a8, a5, 40001415 -40001403: 150867 bnone a8, a6, 4000141c -40001406: 0a89 s32i.n a8, a10, 0 -40001408: 010877 bnone a8, a7, 4000140d -4000140b: aa4b addi.n a10, a10, 4 -4000140d: f01d retw.n -4000140f: 4a8200 madd.s f8, f2, f0 -40001412: f01d00 subx8 a1, a13, a0 -40001415: 005a82 s16i a8, a10, 0 -40001418: f01d retw.n -4000141a: 820000 mull a0, a0, a0 -4000141d: 005a add.n a0, a0, a5 -4000141f: 080c movi.n a8, 0 -40001421: 024a82 s8i a8, a10, 2 -40001424: f01d retw.n -40001426: 0c0000 lsi f0, a0, 48 -40001429: 7608 l32i.n a0, a6, 28 -4000142b: 0c88 l32i.n a8, a12, 0 -4000142d: 000382 l8ui a8, a3, 0 -40001430: 331b addi.n a3, a3, 1 -40001432: 004a82 s8i a8, a10, 0 -40001435: aa1b addi.n a10, a10, 1 -40001437: fff816 beqz a8, 4000143a -4000143a: f01d retw.n - -4000143c : -4000143c: 004136 entry a1, 32 -4000143f: 0aa4e5 call8 4000be8c <__getreent> -40001442: 20b220 or a11, a2, a2 -40001445: 0000a5 call8 40001450 <_strdup_r> -40001448: 202aa0 or a2, a10, a10 -4000144b: f01d retw.n -4000144d: 000000 ill - -40001450 <_strdup_r>: -40001450: 004136 entry a1, 32 -40001453: 20a330 or a10, a3, a3 -40001456: 0006a5 call8 400014c0 -40001459: 01ca42 addi a4, a10, 1 -4000145c: 04bd mov.n a11, a4 -4000145e: 02ad mov.n a10, a2 -40001460: 0a7525 call8 4000bbb4 <_malloc_r> -40001463: 0a2d mov.n a2, a10 -40001465: 5a8c beqz.n a10, 4000146e <_strdup_r+0x1e> -40001467: 03bd mov.n a11, a3 -40001469: 04cd mov.n a12, a4 -4000146b: 0ae5e5 call8 4000c2c8 -4000146e: f01d retw.n - -40001470 : -40001470: 004136 entry a1, 32 -40001473: 03ad mov.n a10, a3 -40001475: b24a add.n a11, a2, a4 -40001477: 028d mov.n a8, a2 -40001479: 000046 j 4000147e -4000147c: 881b addi.n a8, a8, 1 -4000147e: 0e98b7 bne a8, a11, 40001490 -40001481: c02820 sub a2, a8, a2 -40001484: c04420 sub a4, a4, a2 -40001487: 0a9d mov.n a9, a10 -40001489: 34ec bnez.n a4, 400014b0 -4000148b: 0002c6 j 4000149a -4000148e: 920000 lsi f0, a0, 0x248 -40001491: 0008 l32i.n a0, a0, 0 -40001493: fe5956 bnez a9, 4000147c -40001496: fff9c6 j 40001481 -40001499: 026500 andb b6, b5, b0 -4000149c: 2a2a00 mul.s f2, f10, f0 -4000149f: f01d retw.n -400014a1: 000000 ill -400014a4: 061426 beqi a4, 1, 400014ae -400014a7: 0048b2 s8i a11, a8, 0 -400014aa: 440b addi.n a4, a4, -1 -400014ac: 881b addi.n a8, a8, 1 -400014ae: 991b addi.n a9, a9, 1 -400014b0: 0009b2 l8ui a11, a9, 0 -400014b3: fedb56 bnez a11, 400014a4 -400014b6: c099a0 sub a9, a9, a10 -400014b9: 0048b2 s8i a11, a8, 0 -400014bc: 292a add.n a2, a9, a2 -400014be: f01d retw.n - -400014c0 : -400014c0: 002136 entry a1, 16 -400014c3: fcc232 addi a3, a2, -4 -400014c6: ffa042 movi a4, 255 -400014c9: fc5a51 l32r a5, 40000634 <_stext+0xd4> -400014cc: fc5b61 l32r a6, 40000638 <_stext+0xd8> -400014cf: fc5b71 l32r a7, 4000063c <_stext+0xdc> -400014d2: 06e207 bbsi a2, 0, 400014dc -400014d5: 0de217 bbsi a2, 1, 400014e6 -400014d8: 000706 j 400014f8 -400014db: 038200 lsi f0, a2, 12 -400014de: 331b04 lsi f0, a11, 204 -400014e1: 88ac beqz.n a8, 4000150d -400014e3: 116317 bbci a3, 1, 400014f8 -400014e6: 332b addi.n a3, a3, 2 -400014e8: 0388 l32i.n a8, a3, 0 -400014ea: 2e0867 bnone a8, a6, 4000151c -400014ed: 078877 bany a8, a7, 400014f8 -400014f0: 333b addi.n a3, a3, 3 -400014f2: c02320 sub a2, a3, a2 -400014f5: f01d retw.n -400014f7: 080c00 lsx f0, a12, a0 -400014fa: 0f8876 loop a8, 4000150d -400014fd: 1388 l32i.n a8, a3, 4 -400014ff: 334b addi.n a3, a3, 4 -40001501: 0a0847 bnone a8, a4, 4000150f -40001504: 0c0857 bnone a8, a5, 40001514 -40001507: 110867 bnone a8, a6, 4000151c -4000150a: ff0877 bnone a8, a7, 4000150d -4000150d: 333b addi.n a3, a3, 3 -4000150f: c02320 sub a2, a3, a2 -40001512: f01d retw.n -40001514: 331b addi.n a3, a3, 1 -40001516: c02320 sub a2, a3, a2 -40001519: f01d retw.n -4000151b: 332b00 clamps a2, a11, 7 -4000151e: c02320 sub a2, a3, a2 -40001521: f01d retw.n - ... - -40001524 : -40001524: 004136 entry a1, 32 -40001527: fc3081 l32r a8, 400005e8 <_stext+0x88> -4000152a: 029d mov.n a9, a2 -4000152c: 08a8 l32i.n a10, a8, 0 -4000152e: 000506 j 40001546 -40001531: ba8a add.n a11, a10, a8 -40001533: 010bc2 l8ui a12, a11, 1 -40001536: 20c8b2 addi a11, a8, 32 -40001539: 14c0c0 extui a12, a12, 0, 2 -4000153c: cc0b addi.n a12, a12, -1 -4000153e: 838bc0 moveqz a8, a11, a12 -40001541: 004982 s8i a8, a9, 0 -40001544: 991b addi.n a9, a9, 1 -40001546: 000982 l8ui a8, a9, 0 -40001549: fe4856 bnez a8, 40001531 -4000154c: f01d retw.n - ... - -40001550 : -40001550: 004136 entry a1, 32 -40001553: 02cd mov.n a12, a2 -40001555: fc2421 l32r a2, 400005e8 <_stext+0x88> -40001558: 080c movi.n a8, 0 -4000155a: 02a8 l32i.n a10, a2, 0 -4000155c: 000d46 j 40001595 -4000155f: 2c8a00 lsi f0, a10, 176 -40001562: 000292 l8ui a9, a2, 0 -40001565: 2a9a add.n a2, a10, a9 -40001567: 010222 l8ui a2, a2, 1 -4000156a: 20c9b2 addi a11, a9, 32 -4000156d: 142020 extui a2, a2, 0, 2 -40001570: 220b addi.n a2, a2, -1 -40001572: 839b20 moveqz a9, a11, a2 -40001575: 092d mov.n a2, a9 -40001577: 938a add.n a9, a3, a8 -40001579: 000992 l8ui a9, a9, 0 -4000157c: ba9a add.n a11, a10, a9 -4000157e: 010bb2 l8ui a11, a11, 1 -40001581: 20c9d2 addi a13, a9, 32 -40001584: 14b0b0 extui a11, a11, 0, 2 -40001587: bb0b addi.n a11, a11, -1 -40001589: 839db0 moveqz a9, a13, a11 -4000158c: c02290 sub a2, a2, a9 -4000158f: 72cc bnez.n a2, 4000159a -40001591: 881b addi.n a8, a8, 1 -40001593: 398c beqz.n a9, 4000159a -40001595: c79847 bne a8, a4, 40001560 -40001598: 020c movi.n a2, 0 -4000159a: f01d retw.n -4000159c: 000382 l8ui a8, a3, 0 -4000159f: 331b addi.n a3, a3, 1 -400015a1: 004a82 s8i a8, a10, 0 -400015a4: 440b addi.n a4, a4, -1 -400015a6: 74ac beqz.n a4, 400015d1 -400015a8: aa1b addi.n a10, a10, 1 -400015aa: 048816 beqz a8, 400015f6 -400015ad: 3d6317 bbci a3, 1, 400015ee -400015b0: 000382 l8ui a8, a3, 0 -400015b3: 440b addi.n a4, a4, -1 -400015b5: 004a82 s8i a8, a10, 0 -400015b8: 549c beqz.n a4, 400015d1 -400015ba: aa1b addi.n a10, a10, 1 -400015bc: 68bc beqz.n a8, 400015f6 -400015be: 010382 l8ui a8, a3, 1 -400015c1: 332b addi.n a3, a3, 2 -400015c3: 004a82 s8i a8, a10, 0 -400015c6: 440b addi.n a4, a4, -1 -400015c8: 548c beqz.n a4, 400015d1 -400015ca: aa1b addi.n a10, a10, 1 -400015cc: e8dc bnez.n a8, 400015ee -400015ce: 000906 j 400015f6 -400015d1: f01d retw.n - ... - -400015d4 : -400015d4: 002136 entry a1, 16 -400015d7: 02ad mov.n a10, a2 -400015d9: ff4416 beqz a4, 400015d1 -400015dc: ffa0b2 movi a11, 255 -400015df: fc1551 l32r a5, 40000634 <_stext+0xd4> -400015e2: fc1561 l32r a6, 40000638 <_stext+0xd8> -400015e5: fc1571 l32r a7, 4000063c <_stext+0xdc> -400015e8: b0e307 bbsi a3, 0, 4000159c -400015eb: c1e317 bbsi a3, 1, 400015b0 -400015ee: 380c movi.n a8, 3 -400015f0: 540a87 bnone a10, a8, 40001648 -400015f3: 002746 j 40001694 -400015f6: 090c movi.n a9, 0 -400015f8: 28ea07 bbsi a10, 0, 40001624 -400015fb: 32ea17 bbsi a10, 1, 40001631 -400015fe: 1344a6 blti a4, 4, 40001615 -40001601: 218240 srai a8, a4, 2 -40001604: f03d nop.n -40001606: 038876 loop a8, 4000160d -40001609: 0a99 s32i.n a9, a10, 0 -4000160b: aa4b addi.n a10, a10, 4 -4000160d: 1188e0 slli a8, a8, 2 -40001610: c04480 sub a4, a4, a8 -40001613: 948c beqz.n a4, 40001620 -40001615: 004a92 s8i a9, a10, 0 -40001618: 440b addi.n a4, a4, -1 -4000161a: 01caa2 addi a10, a10, 1 -4000161d: ff4456 bnez a4, 40001615 -40001620: f01d retw.n -40001622: 920000 lsi f0, a0, 0x248 -40001625: 004a add.n a0, a0, a4 -40001627: 440b addi.n a4, a4, -1 -40001629: ff3416 beqz a4, 40001620 -4000162c: aa1b addi.n a10, a10, 1 -4000162e: cc6a17 bbci a10, 1, 400015fe -40001631: 004a92 s8i a9, a10, 0 -40001634: 440b addi.n a4, a4, -1 -40001636: fe6416 beqz a4, 40001620 -40001639: 014a92 s8i a9, a10, 1 -4000163c: 440b addi.n a4, a4, -1 -4000163e: fde416 beqz a4, 40001620 -40001641: aa2b addi.n a10, a10, 2 -40001643: ffedc6 j 400015fe -40001646: 0c0000 lsi f0, a0, 48 -40001649: 7608 l32i.n a0, a6, 28 -4000164b: 1988 l32i.n a8, a9, 4 -4000164d: 4354a6 blti a4, 5, 40001694 -40001650: 0388 l32i.n a8, a3, 0 -40001652: 334b addi.n a3, a3, 4 -40001654: 1408b7 bnone a8, a11, 4000166c -40001657: 1d0857 bnone a8, a5, 40001678 -4000165a: 260867 bnone a8, a6, 40001684 -4000165d: 0a89 s32i.n a8, a10, 0 -4000165f: fcc442 addi a4, a4, -4 -40001662: aa4b addi.n a10, a10, 4 -40001664: 8e0877 bnone a8, a7, 400015f6 -40001667: ffe2c6 j 400015f6 -4000166a: 820000 mull a0, a0, a0 -4000166d: 004a add.n a0, a0, a4 -4000166f: 440b addi.n a4, a4, -1 -40001671: aa1b addi.n a10, a10, 1 -40001673: ffdfc6 j 400015f6 -40001676: 820000 mull a0, a0, a0 -40001679: 005a add.n a0, a0, a5 -4000167b: fec442 addi a4, a4, -2 -4000167e: aa2b addi.n a10, a10, 2 -40001680: ffdc86 j 400015f6 -40001683: 5a8200 msub.s f8, f2, f0 -40001686: 080c00 lsx f0, a12, a0 -40001689: 024a82 s8i a8, a10, 2 -4000168c: fdc442 addi a4, a4, -3 -4000168f: aa3b addi.n a10, a10, 3 -40001691: ffd846 j 400015f6 -40001694: 080c movi.n a8, 0 -40001696: 108876 loop a8, 400016aa -40001699: 000382 l8ui a8, a3, 0 -4000169c: 331b addi.n a3, a3, 1 -4000169e: 004a82 s8i a8, a10, 0 -400016a1: 440b addi.n a4, a4, -1 -400016a3: 648c beqz.n a4, 400016ad -400016a5: aa1b addi.n a10, a10, 1 -400016a7: fff816 beqz a8, 400016aa -400016aa: ffd206 j 400015f6 -400016ad: f01d retw.n - ... - -400016b0 : -400016b0: 004136 entry a1, 32 -400016b3: 0a7da5 call8 4000be8c <__getreent> -400016b6: 20b220 or a11, a2, a2 -400016b9: 20c330 or a12, a3, a3 -400016bc: 000065 call8 400016c4 <_strndup_r> -400016bf: 202aa0 or a2, a10, a10 -400016c2: f01d retw.n - -400016c4 <_strndup_r>: -400016c4: 004136 entry a1, 32 -400016c7: 434a add.n a4, a3, a4 -400016c9: 03cd mov.n a12, a3 -400016cb: 000086 j 400016d1 <_strndup_r+0xd> -400016ce: 01ccc2 addi a12, a12, 1 -400016d1: 139c47 bne a12, a4, 400016e8 <_strndup_r+0x24> -400016d4: c04c30 sub a4, a12, a3 -400016d7: 20a220 or a10, a2, a2 -400016da: 01c4b2 addi a11, a4, 1 -400016dd: 0a4d65 call8 4000bbb4 <_malloc_r> -400016e0: 0a2d mov.n a2, a10 -400016e2: cacc bnez.n a10, 400016f2 <_strndup_r+0x2e> -400016e4: f01d retw.n -400016e6: 820000 mull a0, a0, a0 -400016e9: 000c movi.n a0, 0 -400016eb: fdf856 bnez a8, 400016ce <_strndup_r+0xa> -400016ee: fff886 j 400016d4 <_strndup_r+0x10> -400016f1: b33000 movgez a3, a0, a0 -400016f4: c44020 extui a4, a2, 0, 13 -400016f7: bce520 lsi f2, a5, 0x2f0 -400016fa: 400a add.n a4, a0, a0 -400016fc: 0c8042 lsi f4, a0, 48 -400016ff: 443203 lsi f0, a2, 0x110 -40001702: f01d00 subx8 a1, a13, a0 -40001705: 000000 ill - -40001708 : -40001708: 004136 entry a1, 32 -4000170b: 02ad mov.n a10, a2 -4000170d: 020c movi.n a2, 0 -4000170f: 53cc bnez.n a3, 40001718 -40001711: 0004c6 j 40001728 -40001714: a81b addi.n a10, a8, 1 -40001716: 082d mov.n a2, a8 -40001718: 20b330 or a11, a3, a3 -4000171b: 0ae225 call8 4000c53c -4000171e: 208aa0 or a8, a10, a10 -40001721: fefa56 bnez a10, 40001714 -40001724: 000090 retw -40001727: b33000 movgez a3, a0, a0 -4000172a: e12520 lsi f2, a5, 0x384 -4000172d: a00a add.n a10, a0, a0 -4000172f: 202a add.n a2, a0, a2 -40001731: 000090 retw - -40001734 : -40001734: 004136 entry a1, 32 -40001737: 0022a2 l32i a10, a2, 0 -4000173a: 20c220 or a12, a2, a2 -4000173d: 20b330 or a11, a3, a3 -40001740: 0d0c movi.n a13, 0 -40001742: 0af665 call8 4000c6a8 <__strtok_r> -40001745: 0a2d mov.n a2, a10 -40001747: f01d retw.n -40001749: 000000 ill - -4000174c : -4000174c: 004136 entry a1, 32 -4000174f: fba681 l32r a8, 400005e8 <_stext+0x88> -40001752: 029d mov.n a9, a2 -40001754: 08a8 l32i.n a10, a8, 0 -40001756: 000546 j 4000176f -40001759: ba8a add.n a11, a10, a8 -4000175b: 010bc2 l8ui a12, a11, 1 -4000175e: e0c8b2 addi a11, a8, -32 -40001761: 14c0c0 extui a12, a12, 0, 2 -40001764: feccc2 addi a12, a12, -2 -40001767: 838bc0 moveqz a8, a11, a12 -4000176a: 004982 s8i a8, a9, 0 -4000176d: 991b addi.n a9, a9, 1 -4000176f: 000982 l8ui a8, a9, 0 -40001772: fe3856 bnez a8, 40001759 -40001775: f01d retw.n - ... - -40001778 : -40001778: 004136 entry a1, 32 -4000177b: 0a7125 call8 4000be8c <__getreent> -4000177e: 20b220 or a11, a2, a2 -40001781: 0a5ba5 call8 4000bd3c <_close_r> -40001784: 202aa0 or a2, a10, a10 -40001787: f01d retw.n -40001789: 000000 ill - -4000178c : -4000178c: 00a136 entry a1, 80 -4000178f: 9179 s32i.n a7, a1, 36 -40001791: 10c172 addi a7, a1, 16 -40001794: 1179 s32i.n a7, a1, 4 -40001796: 30c172 addi a7, a1, 48 -40001799: 0179 s32i.n a7, a1, 0 -4000179b: 870c movi.n a7, 8 -4000179d: 6149 s32i.n a4, a1, 24 -4000179f: 7159 s32i.n a5, a1, 28 -400017a1: 8169 s32i.n a6, a1, 32 -400017a3: 2179 s32i.n a7, a1, 8 -400017a5: 0a6e65 call8 4000be8c <__getreent> -400017a8: 2188 l32i.n a8, a1, 8 -400017aa: 891c movi.n a9, 24 -400017ac: d84b addi.n a13, a8, 4 -400017ae: 21d9 s32i.n a13, a1, 8 -400017b0: 0529d7 blt a9, a13, 400017b9 -400017b3: 1188 l32i.n a8, a1, 4 -400017b5: 000286 j 400017c3 -400017b8: 298700 lsi f0, a7, 164 -400017bb: 472c03 lsi f0, a12, 0x11c -400017be: 2179 s32i.n a7, a1, 8 -400017c0: 002182 l32i a8, a1, 0 -400017c3: 022172 l32i a7, a1, 8 -400017c6: 20b220 or a11, a2, a2 -400017c9: 887a add.n a8, a8, a7 -400017cb: fcc882 addi a8, a8, -4 -400017ce: 08d8 l32i.n a13, a8, 0 -400017d0: 03cd mov.n a12, a3 -400017d2: 0a5825 call8 4000bd54 <_open_r> -400017d5: 0a2d mov.n a2, a10 -400017d7: f01d retw.n -400017d9: 000000 ill - -400017dc : -400017dc: 004136 entry a1, 32 -400017df: 0a6ae5 call8 4000be8c <__getreent> -400017e2: 20b220 or a11, a2, a2 -400017e5: 20c330 or a12, a3, a3 -400017e8: 04dd mov.n a13, a4 -400017ea: 0a5be5 call8 4000bda8 <_read_r> -400017ed: 0a2d mov.n a2, a10 -400017ef: f01d retw.n -400017f1: 000000 ill - -400017f4 : -400017f4: 004136 entry a1, 32 -400017f7: 0a6965 call8 4000be8c <__getreent> -400017fa: 20b220 or a11, a2, a2 -400017fd: 0a4e65 call8 4000bce4 <_sbrk_r> -40001800: 202aa0 or a2, a10, a10 -40001803: f01d retw.n -40001805: 000000 ill - -40001808 : -40001808: 004136 entry a1, 32 -4000180b: 0a6825 call8 4000be8c <__getreent> -4000180e: 20b220 or a11, a2, a2 -40001811: 0a42e5 call8 4000bc40 <_times_r> -40001814: 202aa0 or a2, a10, a10 -40001817: f01d retw.n -40001819: 000000 ill - -4000181c : -4000181c: 004136 entry a1, 32 -4000181f: 0a66e5 call8 4000be8c <__getreent> -40001822: 20b220 or a11, a2, a2 -40001825: 20c330 or a12, a3, a3 -40001828: 04dd mov.n a13, a4 -4000182a: 0a5465 call8 4000bd70 <_write_r> -4000182d: 0a2d mov.n a2, a10 -4000182f: f01d retw.n -40001831: 000000 ill - -40001834 <__get_current_time_locale>: -40001834: 004136 entry a1, 32 -40001837: fb8321 l32r a2, 40000644 <_stext+0xe4> -4000183a: f01d retw.n - -4000183c <__time_load_locale>: -4000183c: 004136 entry a1, 32 -4000183f: 020c movi.n a2, 0 -40001841: f01d retw.n - ... - -40001844