From Neil.Craig at bbc.co.uk Tue Oct 1 10:43:38 2019 From: Neil.Craig at bbc.co.uk (Neil Craig) Date: Tue, 1 Oct 2019 10:43:38 +0000 Subject: ESNI support Message-ID: Hi Do the NGINX team currently know if it's likely that NGINX will support ESNI once e.g. OpenSSL supports it and if so, whether it'll need any work on the NGINX side? ?https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ Cheers Neil Craig Lead Technical Architect BBC Online Technology Group London W12 | BC4 A3 -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Oct 1 13:07:51 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 1 Oct 2019 16:07:51 +0300 Subject: ESNI support In-Reply-To: References: Message-ID: <20191001130751.GQ1877@mdounin.ru> Hello! On Tue, Oct 01, 2019 at 10:43:38AM +0000, Neil Craig wrote: > Do the NGINX team currently know if it's likely that NGINX will support ESNI once e.g. OpenSSL supports it and if so, whether it'll need any work on the NGINX side? > ?https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ Yes, we do plan to support ESNI once an API is available in OpenSSL (and/or LibreSSL / BoringSSL). Certainly this will need at least some work at nginx side to configure keys. -- Maxim Dounin http://mdounin.ru/ From Neil.Craig at bbc.co.uk Tue Oct 1 13:27:39 2019 From: Neil.Craig at bbc.co.uk (Neil Craig) Date: Tue, 1 Oct 2019 13:27:39 +0000 Subject: ESNI support In-Reply-To: <20191001130751.GQ1877@mdounin.ru> References: <20191001130751.GQ1877@mdounin.ru> Message-ID: Thanks for confirming, that?s what I was expecting but wanted to confirm as we have some teams who are keen to use ESNI. Cheers Neil Craig Lead Technical Architect BBC Online Technology Group London W12 | BC4 A3 On 01/10/2019, 14:07, "nginx-devel on behalf of Maxim Dounin" wrote: >Hello! > >On Tue, Oct 01, 2019 at 10:43:38AM +0000, Neil Craig wrote: > >> Do the NGINX team currently know if it's likely that NGINX will support >>ESNI once e.g. OpenSSL supports it and if so, whether it'll need any >>work on the NGINX side? >> ?https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ > >Yes, we do plan to support ESNI once an API is available in >OpenSSL (and/or LibreSSL / BoringSSL). Certainly this will need >at least some work at nginx side to configure keys. > >-- >Maxim Dounin >http://mdounin.ru/ >_______________________________________________ >nginx-devel mailing list >nginx-devel at nginx.org >http://mailman.nginx.org/mailman/listinfo/nginx-devel From alexander.borisov at nginx.com Thu Oct 3 12:42:05 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 03 Oct 2019 12:42:05 +0000 Subject: [njs] Fixed buffer overflow in Number.prototype.toString(radix). Message-ID: details: https://hg.nginx.org/njs/rev/5f0812d53158 branches: changeset: 1167:5f0812d53158 user: Alexander Borisov date: Thu Oct 03 15:41:30 2019 +0300 description: Fixed buffer overflow in Number.prototype.toString(radix). diffstat: src/njs_number.c | 121 ++++++++++++++++++++++++++++++++++------------ src/test/njs_unit_test.c | 37 ++++++++++++++ 2 files changed, 126 insertions(+), 32 deletions(-) diffs (222 lines): diff -r 5c22e2f006fe -r 5f0812d53158 src/njs_number.c --- a/src/njs_number.c Fri Sep 27 22:21:55 2019 +0300 +++ b/src/njs_number.c Thu Oct 03 15:41:30 2019 +0300 @@ -6,6 +6,7 @@ #include +#include /* @@ -637,30 +638,52 @@ njs_number_prototype_to_fixed(njs_vm_t * /* - * The radix equal to 2 produces the longest intergral value of a number - * and the maximum value consists of 1024 digits and minus sign. + * The radix equal to 2 produces the longest value for a number. */ #define NJS_STRING_RADIX_INTERGRAL_LEN (1 + 1024) -#define NJS_STRING_RADIX_FRACTION_LEN (1 + 54) +#define NJS_STRING_RADIX_FRACTION_LEN (1 + 1075) #define NJS_STRING_RADIX_LEN \ (NJS_STRING_RADIX_INTERGRAL_LEN + NJS_STRING_RADIX_FRACTION_LEN) +njs_inline double +njs_number_next_double(double n) +{ + njs_diyfp_t v; + + v = njs_d2diyfp(n); + + if (signbit(n)) { + if (v.significand == 0) { + return 0.0; + } + + v.significand--; + + } else { + v.significand++; + } + + return njs_diyfp2d(v); +} + + static njs_int_t njs_number_to_string_radix(njs_vm_t *vm, njs_value_t *string, double number, uint32_t radix) { - u_char *p, *f, *end; - double n, next; - size_t size; - uint8_t reminder; - u_char buf[NJS_STRING_RADIX_LEN]; + int digit; + char ch; + double n, remainder, integer, fraction, delta; + u_char *p, *end; + uint32_t size; + u_char buf[NJS_STRING_RADIX_LEN]; static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; - end = buf + NJS_STRING_RADIX_LEN; p = buf + NJS_STRING_RADIX_INTERGRAL_LEN; + end = p; n = number; @@ -668,35 +691,69 @@ njs_number_to_string_radix(njs_vm_t *vm, n = -n; } + integer = floor(n); + fraction = n - integer; + + delta = 0.5 * (njs_number_next_double(n) - n); + delta = njs_max(njs_number_next_double(0.0), delta); + + if (fraction >= delta) { + *p++ = '.'; + + do { + fraction *= radix; + delta *= radix; + + digit = (int) fraction; + *p++ = digits[digit]; + + fraction -= digit; + + if ((fraction > 0.5 || (fraction == 0.5 && (digit & 1))) + && (fraction + delta > 1)) + { + while (p-- != buf) { + if (p == buf + NJS_STRING_RADIX_INTERGRAL_LEN) { + integer += 1; + break; + } + + ch = *p; + digit = (ch > '9') ? ch - 'a' + 10 : ch - '0'; + + if ((uint32_t) (digit + 1) < radix) { + *p++ = digits[digit + 1]; + break; + } + } + + break; + } + + } while (fraction >= delta); + + end = p; + } + + p = buf + NJS_STRING_RADIX_INTERGRAL_LEN; + + while (njs_d2diyfp(integer / radix).exp > 0) { + integer /= radix; + *(--p) = '0'; + } + do { - next = trunc(n / radix); - reminder = n - next * radix; - *(--p) = digits[reminder]; - n = next; - } while (n != 0); + remainder = fmod(integer, radix); + *(--p) = digits[(int) remainder]; + integer = (integer - remainder) / radix; - n = number; + } while (integer > 0); - if (n < 0) { + if (number < 0) { *(--p) = '-'; } - f = buf + NJS_STRING_RADIX_INTERGRAL_LEN; - - n = n - trunc(n); - - if (n != 0) { - *f++ = '.'; - - do { - n = n * radix; - reminder = trunc(n); - *f++ = digits[reminder]; - n = n - reminder; - } while (n != 0 && f < end); - } - - size = f - p; + size = (uint32_t) (end - p); return njs_string_new(vm, string, p, size, size); } diff -r 5c22e2f006fe -r 5f0812d53158 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Sep 27 22:21:55 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 03 15:41:30 2019 +0300 @@ -361,8 +361,10 @@ static njs_unit_test_t njs_test[] = /* Number.toString(radix) method. */ +#ifndef NJS_SUNC { njs_str("0..toString(2)"), njs_str("0") }, +#endif { njs_str("240..toString(2)"), njs_str("11110000") }, @@ -427,6 +429,41 @@ static njs_unit_test_t njs_test[] = { njs_str("NaN.toString(NaN)"), njs_str("RangeError") }, + { njs_str("1.2312313132.toString(14)"), + njs_str("1.3346da6d5d455c") }, + + { njs_str("7.799999999999999.toString(14)"), + njs_str("7.b2b2b2b2b2b2a5") }, + +#ifndef NJS_SUNC + { njs_str("1e20.toString(14)"), + njs_str("33cb3bb449c2a92000") }, + + /* Smallest positive double (next_double(0)). */ + { njs_str("4.94065645841246544176568792868E-324.toString(36) == ('0.' + '0'.repeat(207) +'3')"), + njs_str("true") }, + + { njs_str("1.7976931348623157E+308.toString(36) == ('1a1e4vngaiqo' + '0'.repeat(187))"), + njs_str("true") }, + + /* Largest positive double (prev_double(INFINITY)). */ + { njs_str("1.7976931348623157E+308.toString(2) == ('1'.repeat(53) + '0'.repeat(971))"), + njs_str("true") }, + + /* Maximum fraction length. */ + { njs_str("2.2250738585072014E-323.toString(2) == ('0.' + '0'.repeat(1071) + '101')"), + njs_str("true") }, + + { njs_str("2.2250738585072014E-308.toString(2) == ('0.' + '0'.repeat(1021) + '1')"), + njs_str("true") }, + + { njs_str("Array(5).fill().map((n, i) => i + 10).map((v)=>(1.2312313132).toString(v))"), + njs_str("1.2312313132,1.25a850416057383,1.293699002749414,1.3010274cab0288,1.3346da6d5d455c") }, + + { njs_str("Array(5).fill().map((n, i) => 36 - i).map((v)=>(1e23).toString(v))"), + njs_str("ga894a06abs0000,o5hlsorok4y0000,128fpsprqld20000,1m1s0ajv6cmo0000,2kmg5hv19br00000") }, +#endif + /* Number.prototype.toFixed(frac) method. */ { njs_str("(900.1).toFixed(1)"), From xeioex at nginx.com Thu Oct 3 13:59:38 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 03 Oct 2019 13:59:38 +0000 Subject: [njs] Improved naming in njs_dtoa() internal functions. Message-ID: details: https://hg.nginx.org/njs/rev/cb7874a63d2b branches: changeset: 1168:cb7874a63d2b user: Dmitry Volyntsev date: Thu Oct 03 16:26:04 2019 +0300 description: Improved naming in njs_dtoa() internal functions. diffstat: src/njs_dtoa.c | 127 +++++++++++++++++++++++++++----------------------------- src/njs_dtoa.h | 2 +- 2 files changed, 63 insertions(+), 66 deletions(-) diffs (242 lines): diff -r 5f0812d53158 -r cb7874a63d2b src/njs_dtoa.c --- a/src/njs_dtoa.c Thu Oct 03 15:41:30 2019 +0300 +++ b/src/njs_dtoa.c Thu Oct 03 16:26:04 2019 +0300 @@ -40,14 +40,14 @@ njs_inline void -njs_grisu2_round(char *start, size_t len, uint64_t delta, uint64_t rest, - uint64_t ten_kappa, uint64_t wp_w) +njs_round(char *start, size_t length, uint64_t delta, uint64_t rest, + uint64_t ten_kappa, uint64_t margin) { - while (rest < wp_w && delta - rest >= ten_kappa - && (rest + ten_kappa < wp_w || /* closer */ - wp_w - rest > rest + ten_kappa - wp_w)) + while (rest < margin && delta - rest >= ten_kappa + && (rest + ten_kappa < margin || /* closer */ + margin - rest > rest + ten_kappa - margin)) { - start[len - 1]--; + start[length - 1]--; rest += ten_kappa; } } @@ -81,14 +81,14 @@ njs_dec_count(uint32_t n) njs_inline size_t -njs_grisu2_gen(njs_diyfp_t W, njs_diyfp_t Mp, uint64_t delta, char *start, +njs_digit_gen(njs_diyfp_t v, njs_diyfp_t high, uint64_t delta, char *start, int *dec_exp) { int kappa; - char c, *p; - uint32_t p1, d; - uint64_t p2, tmp; - njs_diyfp_t one, wp_w; + char *p; + uint32_t integer, d; + uint64_t fraction, rest, margin; + njs_diyfp_t one; static const uint64_t pow10[] = { 1, @@ -103,34 +103,29 @@ njs_grisu2_gen(njs_diyfp_t W, njs_diyfp_ 1000000000 }; - wp_w = njs_diyfp_sub(Mp, W); + one = njs_diyfp((uint64_t) 1 << -high.exp, high.exp); + integer = (uint32_t) (high.significand >> -one.exp); + fraction = high.significand & (one.significand - 1); - one = njs_diyfp((uint64_t) 1 << -Mp.exp, Mp.exp); - p1 = (uint32_t) (Mp.significand >> -one.exp); - p2 = Mp.significand & (one.significand - 1); + margin = njs_diyfp_sub(high, v).significand; p = start; - /* GCC 4.2 complains about uninitialized d. */ - d = 0; - - kappa = njs_dec_count(p1); + kappa = njs_dec_count(integer); while (kappa > 0) { switch (kappa) { - case 10: d = p1 / 1000000000; p1 %= 1000000000; break; - case 9: d = p1 / 100000000; p1 %= 100000000; break; - case 8: d = p1 / 10000000; p1 %= 10000000; break; - case 7: d = p1 / 1000000; p1 %= 1000000; break; - case 6: d = p1 / 100000; p1 %= 100000; break; - case 5: d = p1 / 10000; p1 %= 10000; break; - case 4: d = p1 / 1000; p1 %= 1000; break; - case 3: d = p1 / 100; p1 %= 100; break; - case 2: d = p1 / 10; p1 %= 10; break; - case 1: d = p1; p1 = 0; break; - default: - njs_unreachable(); + case 10: d = integer / 1000000000; integer %= 1000000000; break; + case 9: d = integer / 100000000; integer %= 100000000; break; + case 8: d = integer / 10000000; integer %= 10000000; break; + case 7: d = integer / 1000000; integer %= 1000000; break; + case 6: d = integer / 100000; integer %= 100000; break; + case 5: d = integer / 10000; integer %= 10000; break; + case 4: d = integer / 1000; integer %= 1000; break; + case 3: d = integer / 100; integer %= 100; break; + case 2: d = integer / 10; integer %= 10; break; + default: d = integer; integer = 0; break; } if (d != 0 || p != start) { @@ -139,12 +134,12 @@ njs_grisu2_gen(njs_diyfp_t W, njs_diyfp_ kappa--; - tmp = ((uint64_t) p1 << -one.exp) + p2; + rest = ((uint64_t) integer << -one.exp) + fraction; - if (tmp <= delta) { + if (rest < delta) { *dec_exp += kappa; - njs_grisu2_round(start, p - start, delta, tmp, - pow10[kappa] << -one.exp, wp_w.significand); + njs_round(start, p - start, delta, rest, pow10[kappa] << -one.exp, + margin); return p - start; } } @@ -152,27 +147,26 @@ njs_grisu2_gen(njs_diyfp_t W, njs_diyfp_ /* kappa = 0. */ for ( ;; ) { - p2 *= 10; + fraction *= 10; delta *= 10; - c = (char) (p2 >> -one.exp); + + d = (uint32_t) (fraction >> -one.exp); - if (c != 0 || p != start) { - *p++ = '0' + c; + if (d != 0 || p != start) { + *p++ = '0' + d; } - p2 &= one.significand - 1; + fraction &= one.significand - 1; kappa--; - if (p2 < delta) { + if (fraction < delta) { *dec_exp += kappa; - tmp = (-kappa < 10) ? pow10[-kappa] : 0; - njs_grisu2_round(start, p - start, delta, p2, one.significand, - wp_w.significand * tmp); - break; + margin *= (-kappa < 10) ? pow10[-kappa] : 0; + njs_round(start, p - start, delta, fraction, one.significand, + margin); + return p - start; } } - - return p - start; } @@ -212,26 +206,31 @@ njs_diyfp_normalize_boundaries(njs_diyfp } +/* + * Grisu2 produces optimal (shortest) decimal representation for 99.8% + * of IEEE doubles. For remaining 0.2% bignum algorithm like Dragon4 is requred. + */ njs_inline size_t njs_grisu2(double value, char *start, int *dec_exp) { - njs_diyfp_t v, w_m, w_p, c_mk, W, Wp, Wm; + njs_diyfp_t v, low, high, ten_mk, scaled_v, scaled_low, scaled_high; v = njs_d2diyfp(value); - njs_diyfp_normalize_boundaries(v, &w_m, &w_p); + njs_diyfp_normalize_boundaries(v, &low, &high); - c_mk = njs_cached_power_bin(w_p.exp, dec_exp); - W = njs_diyfp_mul(njs_diyfp_normalize(v), c_mk); + ten_mk = njs_cached_power_bin(high.exp, dec_exp); - Wp = njs_diyfp_mul(w_p, c_mk); - Wm = njs_diyfp_mul(w_m, c_mk); + scaled_v = njs_diyfp_mul(njs_diyfp_normalize(v), ten_mk); + scaled_low = njs_diyfp_mul(low, ten_mk); + scaled_high = njs_diyfp_mul(high, ten_mk); - Wm.significand++; - Wp.significand--; + scaled_low.significand++; + scaled_high.significand--; - return njs_grisu2_gen(W, Wp, Wp.significand - Wm.significand, start, - dec_exp); + return njs_digit_gen(scaled_v, scaled_high, + scaled_high.significand - scaled_low.significand, + start, dec_exp); } @@ -239,7 +238,7 @@ njs_inline size_t njs_write_exponent(int exp, char *start) { char *p; - size_t len; + size_t length; uint32_t u32; char buf[4]; @@ -261,16 +260,16 @@ njs_write_exponent(int exp, char *start) u32 /= 10; } while (u32 != 0); - len = buf + njs_length(buf) - p; + length = buf + njs_length(buf) - p; - memcpy(start, p, len); + memcpy(start, p, length); - return len + 1; + return length + 1; } njs_inline size_t -njs_prettify(char *start, size_t len, int dec_exp) +njs_dtoa_format(char *start, size_t len, int dec_exp) { int kk, offset, length; size_t size; @@ -365,7 +364,5 @@ njs_dtoa(double value, char *start) length = njs_grisu2(value, p, &dec_exp); - length = njs_prettify(p, length, dec_exp); - - return minus + length; + return njs_dtoa_format(p, length, dec_exp) + minus; } diff -r 5f0812d53158 -r cb7874a63d2b src/njs_dtoa.h --- a/src/njs_dtoa.h Thu Oct 03 15:41:30 2019 +0300 +++ b/src/njs_dtoa.h Thu Oct 03 16:26:04 2019 +0300 @@ -7,6 +7,6 @@ #ifndef _NJS_DTOA_H_INCLUDED_ #define _NJS_DTOA_H_INCLUDED_ -NJS_EXPORT size_t njs_dtoa(double value, char *buffer); +NJS_EXPORT size_t njs_dtoa(double value, char *start); #endif /* _NJS_DTOA_H_INCLUDED_ */ From xeioex at nginx.com Thu Oct 3 13:59:39 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 03 Oct 2019 13:59:39 +0000 Subject: [njs] Added Number.prototype.toPrecision(). Message-ID: details: https://hg.nginx.org/njs/rev/956b24477d59 branches: changeset: 1169:956b24477d59 user: Dmitry Volyntsev date: Thu Oct 03 16:59:22 2019 +0300 description: Added Number.prototype.toPrecision(). This closes #221 issue on Github. diffstat: src/njs_dtoa.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++ src/njs_dtoa.h | 1 + src/njs_number.c | 56 +++++++++++ src/test/njs_unit_test.c | 85 +++++++++++++++++ 4 files changed, 377 insertions(+), 0 deletions(-) diffs (448 lines): diff -r cb7874a63d2b -r 956b24477d59 src/njs_dtoa.c --- a/src/njs_dtoa.c Thu Oct 03 16:26:04 2019 +0300 +++ b/src/njs_dtoa.c Thu Oct 03 16:59:22 2019 +0300 @@ -53,6 +53,40 @@ njs_round(char *start, size_t length, ui } +njs_inline void +njs_round_prec(char *start, size_t length, uint64_t rest, uint64_t ten_kappa, + uint64_t unit, int *kappa) +{ + njs_int_t i; + + if (unit >= ten_kappa || ten_kappa - unit <= unit) { + return; + } + + if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) { + return; + } + + if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) { + start[length - 1]++; + + for (i = length - 1; i > 0; --i) { + if (start[i] != '0' + 10) { + break; + } + + start[i] = '0'; + start[i - 1]++; + } + + if (start[0] == '0' + 10) { + start[0] = '1'; + *kappa += 1; + } + } +} + + njs_inline int njs_dec_count(uint32_t n) { @@ -170,6 +204,79 @@ njs_digit_gen(njs_diyfp_t v, njs_diyfp_t } +njs_inline size_t +njs_digit_gen_prec(njs_diyfp_t v, size_t prec, char *start, int *dec_exp) +{ + int kappa; + char *p; + uint32_t integer, divisor; + uint64_t fraction, rest, error; + njs_diyfp_t one; + + static const uint64_t pow10[] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; + + one = njs_diyfp((uint64_t) 1 << -v.exp, v.exp); + integer = (uint32_t) (v.significand >> -one.exp); + fraction = v.significand & (one.significand - 1); + + error = 1; + + p = start; + + kappa = njs_dec_count(integer); + + while (kappa > 0) { + divisor = pow10[kappa - 1]; + + *p++ = '0' + integer / divisor; + + integer %= divisor; + + kappa--; + prec--; + + if (prec == 0) { + rest = ((uint64_t) integer << -one.exp) + fraction; + njs_round_prec(start, p - start, rest, pow10[kappa] << -one.exp, + error, &kappa); + + *dec_exp += kappa; + return p - start; + } + } + + /* kappa = 0. */ + + while (prec > 0 && fraction > error) { + fraction *= 10; + error *= 10; + + *p++ = '0' + (fraction >> -one.exp); + + fraction &= one.significand - 1; + kappa--; + prec--; + } + + njs_round_prec(start, p - start, fraction, one.significand, error, &kappa); + + *dec_exp += kappa; + + return p - start; +} + + njs_inline njs_diyfp_t njs_diyfp_normalize_boundary(njs_diyfp_t v) { @@ -235,6 +342,27 @@ njs_grisu2(double value, char *start, in njs_inline size_t +njs_grisu2_prec(double value, char *start, size_t prec, int *point) +{ + int dec_exp; + size_t length; + njs_diyfp_t v, ten_mk, scaled_v; + + v = njs_diyfp_normalize(njs_d2diyfp(value)); + + ten_mk = njs_cached_power_bin(v.exp, &dec_exp); + + scaled_v = njs_diyfp_mul(v, ten_mk); + + length = njs_digit_gen_prec(scaled_v, prec, start, &dec_exp); + + *point = length + dec_exp; + + return length; +} + + +njs_inline size_t njs_write_exponent(int exp, char *start) { char *p; @@ -338,6 +466,78 @@ njs_dtoa_format(char *start, size_t len, } +njs_inline size_t +njs_dtoa_prec_format(char *start, size_t prec, size_t len, int point) +{ + int exponent; + char *p; + size_t m, rest, size; + + exponent = point - 1; + + if (exponent < -6 || exponent >= (int) prec) { + p = &start[len]; + if (prec != 1) { + memmove(&start[2], &start[1], len - 1); + start[1] = '.'; + p++; + } + + njs_memset(p, '0', prec - len); + p += prec - len; + + *p++ = 'e'; + + size = njs_write_exponent(exponent, p); + + return prec + 1 + (prec != 1) + size; + } + + /* Fixed notation. */ + + if (point <= 0) { + /* 1234e-2 => 0.001234000 */ + + memmove(&start[2 + (-point)], start, len); + start[0] = '0'; + start[1] = '.'; + + njs_memset(&start[2], '0', -point); + + if (prec > len) { + njs_memset(&start[2 + (-point) + len], '0', prec - len); + } + + return prec + 2 + (-point); + } + + if (point >= (int) len) { + /* TODO: (2**96).toPrecision(45) not enough precision, BigInt needed. */ + + njs_memset(&start[len], '0', point - len); + + if (point < (int) prec) { + start[point] = '.'; + + njs_memset(&start[point + 1], '0', prec - len); + } + + } else if (point < (int) prec) { + /* 123456 -> 123.45600 */ + + m = njs_min((int) len, point); + rest = njs_min(len, prec) - m; + memmove(&start[m + 1], &start[m], rest); + + start[m] = '.'; + + njs_memset(&start[m + rest + 1], '0', prec - m - rest); + } + + return prec + (point < (int) prec); +} + + size_t njs_dtoa(double value, char *start) { @@ -366,3 +566,38 @@ njs_dtoa(double value, char *start) return njs_dtoa_format(p, length, dec_exp) + minus; } + + +/* + * TODO: For prec > 16 result maybe rounded. To support prec > 16 Bignum + * support is requred. + */ +size_t +njs_dtoa_precision(double value, char *start, size_t prec) +{ + int point, minus; + char *p; + size_t length; + + /* Not handling NaN and inf. */ + + p = start; + minus = 0; + + if (value != 0) { + if (value < 0) { + *p++ = '-'; + value = -value; + minus = 1; + } + + length = njs_grisu2_prec(value, p, prec, &point); + + } else { + start[0] = '0'; + length = 1; + point = 1; + } + + return njs_dtoa_prec_format(p, prec, length, point) + minus; +} diff -r cb7874a63d2b -r 956b24477d59 src/njs_dtoa.h --- a/src/njs_dtoa.h Thu Oct 03 16:26:04 2019 +0300 +++ b/src/njs_dtoa.h Thu Oct 03 16:59:22 2019 +0300 @@ -8,5 +8,6 @@ #define _NJS_DTOA_H_INCLUDED_ NJS_EXPORT size_t njs_dtoa(double value, char *start); +NJS_EXPORT size_t njs_dtoa_precision(double value, char *start, size_t prec); #endif /* _NJS_DTOA_H_INCLUDED_ */ diff -r cb7874a63d2b -r 956b24477d59 src/njs_number.c --- a/src/njs_number.c Thu Oct 03 16:26:04 2019 +0300 +++ b/src/njs_number.c Thu Oct 03 16:59:22 2019 +0300 @@ -637,6 +637,53 @@ njs_number_prototype_to_fixed(njs_vm_t * } +static njs_int_t +njs_number_prototype_to_precision(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + double number; + size_t size; + int32_t precision; + njs_value_t *value; + u_char buf[128]; + + /* 128 > 100 + 21 + njs_length(".-\0"). */ + + value = &args[0]; + + if (value->type != NJS_NUMBER) { + if (value->type == NJS_OBJECT_NUMBER) { + value = njs_object_value(value); + + } else { + njs_type_error(vm, "unexpected value type:%s", + njs_type_string(value->type)); + return NJS_ERROR; + } + } + + if (njs_is_undefined(njs_arg(args, nargs, 1))) { + return njs_number_to_string(vm, &vm->retval, value); + } + + number = njs_number(value); + + if (njs_slow_path(isnan(number) || isinf(number))) { + return njs_number_to_string(vm, &vm->retval, value); + } + + precision = njs_primitive_value_to_integer(njs_argument(args, 1)); + if (njs_slow_path(precision < 1 || precision > 100)) { + njs_range_error(vm, "precision argument must be between 1 and 100"); + return NJS_ERROR; + } + + size = njs_dtoa_precision(number, (char *) buf, precision); + + return njs_string_new(vm, &vm->retval, buf, size, size); +} + + /* * The radix equal to 2 produces the longest value for a number. */ @@ -802,6 +849,15 @@ static const njs_object_prop_t njs_numb .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("toPrecision"), + .value = njs_native_function(njs_number_prototype_to_precision, + NJS_SKIP_ARG, NJS_INTEGER_ARG), + .writable = 1, + .configurable = 1, + }, }; diff -r cb7874a63d2b -r 956b24477d59 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 03 16:26:04 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 03 16:59:22 2019 +0300 @@ -525,6 +525,91 @@ static njs_unit_test_t njs_test[] = njs_str("0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625") }, #endif + /* Number.prototype.toPrecision(prec) method. */ + + { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(1/7).toPrecision(v))"), + njs_str("0.1,0.14,0.143,0.1429") }, + + { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(0).toPrecision(v))"), + njs_str("0,0.0,0.00,0.000") }, + + { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(1/2).toPrecision(v))"), + njs_str("0.5,0.50,0.500,0.5000") }, + + { njs_str("Array(6).fill().map((n, i) => i+2).map((v)=>(1/v).toPrecision(5))"), + njs_str("0.50000,0.33333,0.25000,0.20000,0.16667,0.14286") }, + + { njs_str("Array(6).fill().map((n, i) => i+2).map((v)=>(1/(v*100)).toPrecision(5))"), + njs_str("0.0050000,0.0033333,0.0025000,0.0020000,0.0016667,0.0014286") }, + + { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>(10*v/7).toPrecision(5))"), + njs_str("1.4286,2.8571,4.2857,5.7143,7.1429,8.5714") }, + + { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>(v/3).toPrecision(5))"), + njs_str("0.33333,0.66667,1.0000,1.3333,1.6667,2.0000") }, + + { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toPrecision(5))"), + njs_str("-0.66667,1.3333,-2.0000,2.6667,-3.3333,4.0000") }, + + { njs_str("Array(12).fill().map((n, i) => i-3).map((v)=>(2**v).toPrecision(6))"), + njs_str("0.125000,0.250000,0.500000,1.00000,2.00000,4.00000,8.00000,16.0000,32.0000,64.0000,128.000,256.000") }, + + { njs_str("Array(5).fill().map((n, i) => i+16).map((v)=>(4.1).toPrecision(v))"), + njs_str("4.100000000000000,4.0999999999999996,4.09999999999999964,4.099999999999999644,4.0999999999999996447") }, + + { njs_str("Array(3).fill().map((n, i) => i + 19).map((v)=>(2**(-v)).toPrecision(20))"), + njs_str("0.0000019073486328125000000,9.5367431640625000000e-7,4.7683715820312500000e-7") }, + + { njs_str("Array(3).fill().map((n, i) => i + 32).map((v)=>(2**(v)+0.1).toPrecision(10))"), + njs_str("4294967296,8589934592,1.717986918e+10") }, + +#if 0 /* FIXME: bignum support is requred to support prec >= 20 */ + { njs_str("(1/7).toPrecision(100)"), + njs_str("0.1428571428571428492126926812488818541169166564941406250000000000000000000000000000000000000000000000") }, + + { njs_str("(2**128).toPrecision(40)"), + njs_str("340282366920938463463374607431768211456.0") }, +#endif + + { njs_str("(2**128).toPrecision(1)"), + njs_str("3e+38") }, + + { njs_str("(2**128).toPrecision(2)"), + njs_str("3.4e+38") }, + + { njs_str("(2**128).toPrecision(40)"), + njs_str("340282366920938463490000000000000000000.0") }, + + { njs_str("(123).toPrecision(0)"), + njs_str("RangeError: precision argument must be between 1 and 100") }, + + { njs_str("(123).toPrecision(2.4)"), + njs_str("1.2e+2") }, + + { njs_str("(123).toPrecision(101)"), + njs_str("RangeError: precision argument must be between 1 and 100") }, + + { njs_str("(2**10000).toPrecision()"), + njs_str("Infinity") }, + + { njs_str("(-(2**10000)).toPrecision()"), + njs_str("-Infinity") }, + + { njs_str("(-0).toPrecision(2)"), + njs_str("0.0") }, + + { njs_str("NaN.toPrecision()"), + njs_str("NaN") }, + + { njs_str("NaN.toPrecision(0)"), + njs_str("NaN") }, + + { njs_str("(10**22).toPrecision()"), + njs_str("1e+22") }, + + { njs_str("Number.prototype.toPrecision.call('12')"), + njs_str("TypeError: unexpected value type:string") }, + { njs_str("(1000000000000000128).toString()"), njs_str("1000000000000000100") }, From xeioex at nginx.com Fri Oct 4 14:19:29 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 04 Oct 2019 14:19:29 +0000 Subject: [njs] Fixed Regexp.prototype.test() for regexps with backreferences. Message-ID: details: https://hg.nginx.org/njs/rev/d62db2c99851 branches: changeset: 1170:d62db2c99851 user: Dmitry Volyntsev date: Fri Oct 04 17:19:06 2019 +0300 description: Fixed Regexp.prototype.test() for regexps with backreferences. This closes #225 issue on Github. diffstat: src/njs_pcre.c | 18 ++++++++++++++++++ src/njs_pcre.h | 1 + src/njs_regex.h | 1 + src/njs_regexp.c | 42 ++++++++++++++++++++++++++++++++---------- src/test/njs_unit_test.c | 4 ++++ 5 files changed, 56 insertions(+), 10 deletions(-) diffs (139 lines): diff -r 956b24477d59 -r d62db2c99851 src/njs_pcre.c --- a/src/njs_pcre.c Thu Oct 03 16:59:22 2019 +0300 +++ b/src/njs_pcre.c Fri Oct 04 17:19:06 2019 +0300 @@ -111,6 +111,17 @@ njs_regex_compile(njs_regex_t *regex, u_ goto done; } + err = pcre_fullinfo(regex->code, NULL, PCRE_INFO_BACKREFMAX, + ®ex->backrefmax); + + if (njs_slow_path(err < 0)) { + njs_alert(ctx->trace, NJS_LEVEL_ERROR, + "pcre_fullinfo(\"%s\", PCRE_INFO_BACKREFMAX) failed: %d", + pattern, err); + + goto done; + } + /* Reserve additional elements for the first "$0" capture. */ regex->ncaptures++; @@ -175,6 +186,13 @@ njs_regex_ncaptures(njs_regex_t *regex) } +njs_uint_t +njs_regex_backrefs(njs_regex_t *regex) +{ + return regex->backrefmax; +} + + njs_int_t njs_regex_named_captures(njs_regex_t *regex, njs_str_t *name, int n) { diff -r 956b24477d59 -r d62db2c99851 src/njs_pcre.h --- a/src/njs_pcre.h Thu Oct 03 16:59:22 2019 +0300 +++ b/src/njs_pcre.h Fri Oct 04 17:19:06 2019 +0300 @@ -18,6 +18,7 @@ struct njs_regex_s { pcre *code; pcre_extra *extra; int ncaptures; + int backrefmax; int nentries; int entry_size; char *entries; diff -r 956b24477d59 -r d62db2c99851 src/njs_regex.h --- a/src/njs_regex.h Thu Oct 03 16:59:22 2019 +0300 +++ b/src/njs_regex.h Fri Oct 04 17:19:06 2019 +0300 @@ -31,6 +31,7 @@ NJS_EXPORT njs_int_t njs_regex_compile(n size_t len, njs_uint_t options, njs_regex_context_t *ctx); NJS_EXPORT njs_bool_t njs_regex_is_valid(njs_regex_t *regex); NJS_EXPORT njs_uint_t njs_regex_ncaptures(njs_regex_t *regex); +NJS_EXPORT njs_uint_t njs_regex_backrefs(njs_regex_t *regex); NJS_EXPORT njs_int_t njs_regex_named_captures(njs_regex_t *regex, njs_str_t *name, int n); NJS_EXPORT njs_regex_match_data_t *njs_regex_match_data(njs_regex_t *regex, diff -r 956b24477d59 -r d62db2c99851 src/njs_regexp.c --- a/src/njs_regexp.c Thu Oct 03 16:59:22 2019 +0300 +++ b/src/njs_regexp.c Fri Oct 04 17:19:06 2019 +0300 @@ -842,11 +842,13 @@ static njs_int_t njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_int_t ret; - njs_uint_t n; - const njs_value_t *value, *retval; - njs_string_prop_t string; - njs_regexp_pattern_t *pattern; + njs_int_t ret; + njs_uint_t n; + njs_regex_t *regex; + const njs_value_t *value, *retval; + njs_string_prop_t string; + njs_regexp_pattern_t *pattern; + njs_regex_match_data_t *match_data; if (!njs_is_regexp(njs_arg(args, nargs, 0))) { njs_type_error(vm, "\"this\" argument is not a regexp"); @@ -866,20 +868,40 @@ njs_regexp_prototype_test(njs_vm_t *vm, pattern = njs_regexp_pattern(&args[0]); - if (njs_regex_is_valid(&pattern->regex[n])) { - ret = njs_regexp_match(vm, &pattern->regex[n], string.start, - string.size, vm->single_match_data); + regex = &pattern->regex[n]; + match_data = vm->single_match_data; + + if (njs_regex_is_valid(regex)) { + if (njs_regex_backrefs(regex) != 0) { + match_data = njs_regex_match_data(regex, vm->regex_context); + if (njs_slow_path(match_data == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + } + + ret = njs_regexp_match(vm, regex, string.start, string.size, + match_data); if (ret >= 0) { retval = &njs_value_true; } else if (ret != NJS_REGEX_NOMATCH) { - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } } + ret = NJS_OK; + vm->retval = *retval; - return NJS_OK; +done: + + if (match_data != vm->single_match_data) { + njs_regex_match_data_free(match_data, vm->regex_context); + } + + return ret; } diff -r 956b24477d59 -r d62db2c99851 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 03 16:59:22 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 04 17:19:06 2019 +0300 @@ -8178,6 +8178,10 @@ static njs_unit_test_t njs_test[] = njs_str("true") }, #endif + { njs_str("var re = /<(?[\\w\\-\\.\\:]+)>(?.*?)<\\/\\1>/g;" + "['XXX', 'XX'].map(s=>re.test(s))"), + njs_str("true,false") }, + { njs_str("/\\x80/.test('\\u0080')"), njs_str("true") }, From xeioex at nginx.com Fri Oct 4 16:50:30 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 04 Oct 2019 16:50:30 +0000 Subject: [njs] Increased maximum allowed recursion depth in parser and generator. Message-ID: details: https://hg.nginx.org/njs/rev/5c71fd61dc15 branches: changeset: 1172:5c71fd61dc15 user: Dmitry Volyntsev date: Fri Oct 04 19:46:35 2019 +0300 description: Increased maximum allowed recursion depth in parser and generator. diffstat: src/njs_generator.c | 2 +- src/njs_parser.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r 1cd7640472b8 -r 5c71fd61dc15 src/njs_generator.c --- a/src/njs_generator.c Fri Oct 04 19:46:12 2019 +0300 +++ b/src/njs_generator.c Fri Oct 04 19:46:35 2019 +0300 @@ -513,7 +513,7 @@ njs_generator(njs_vm_t *vm, njs_generato { njs_int_t ret; - if (njs_slow_path(generator->count++ > 1024)) { + if (njs_slow_path(generator->count++ > 4096)) { njs_range_error(vm, "Maximum call stack size exceeded"); return NJS_ERROR; } diff -r 1cd7640472b8 -r 5c71fd61dc15 src/njs_parser.h --- a/src/njs_parser.h Fri Oct 04 19:46:12 2019 +0300 +++ b/src/njs_parser.h Fri Oct 04 19:46:35 2019 +0300 @@ -116,7 +116,7 @@ void njs_parser_node_error(njs_vm_t *vm, #define njs_parser_enter(vm, parser) \ do { \ - if (njs_slow_path((parser)->count++ > 1024)) { \ + if (njs_slow_path((parser)->count++ > 4096)) { \ njs_range_error(vm, "Maximum call stack size exceeded"); \ return NJS_TOKEN_ERROR; \ } \ From xeioex at nginx.com Fri Oct 4 16:50:30 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 04 Oct 2019 16:50:30 +0000 Subject: [njs] Style. Message-ID: details: https://hg.nginx.org/njs/rev/1cd7640472b8 branches: changeset: 1171:1cd7640472b8 user: Dmitry Volyntsev date: Fri Oct 04 19:46:12 2019 +0300 description: Style. Fixed typo in njs_arr_t structure. This closes #226 issue on Github. diffstat: src/njs_arr.c | 10 +++++----- src/njs_arr.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diffs (60 lines): diff -r d62db2c99851 -r 1cd7640472b8 src/njs_arr.c --- a/src/njs_arr.c Fri Oct 04 17:19:06 2019 +0300 +++ b/src/njs_arr.c Fri Oct 04 19:46:12 2019 +0300 @@ -21,7 +21,7 @@ njs_arr_create(njs_mp_t *mp, njs_uint_t arr->start = (char *) arr + sizeof(njs_arr_t); arr->items = 0; arr->item_size = size; - arr->avalaible = n; + arr->available = n; arr->pointer = 1; arr->separate = 1; arr->mem_pool = mp; @@ -37,7 +37,7 @@ njs_arr_init(njs_mp_t *mp, njs_arr_t *ar arr->start = start; arr->items = n; arr->item_size = size; - arr->avalaible = n; + arr->available = n; arr->pointer = 0; arr->separate = 0; arr->mem_pool = mp; @@ -61,7 +61,7 @@ njs_arr_destroy(njs_arr_t *arr) #if (NJS_DEBUG) arr->start = NULL; arr->items = 0; - arr->avalaible = 0; + arr->available = 0; #endif } @@ -84,7 +84,7 @@ njs_arr_add_multiple(njs_arr_t *arr, njs void *item, *start, *old; uint32_t n; - n = arr->avalaible; + n = arr->available; items += arr->items; if (items >= n) { @@ -107,7 +107,7 @@ njs_arr_add_multiple(njs_arr_t *arr, njs return NULL; } - arr->avalaible = n; + arr->available = n; old = arr->start; arr->start = start; diff -r d62db2c99851 -r 1cd7640472b8 src/njs_arr.h --- a/src/njs_arr.h Fri Oct 04 17:19:06 2019 +0300 +++ b/src/njs_arr.h Fri Oct 04 19:46:12 2019 +0300 @@ -15,7 +15,7 @@ typedef struct { * The item size is no more than 64K. */ uint16_t items; - uint16_t avalaible; + uint16_t available; uint16_t item_size; uint8_t pointer; From xeioex at nginx.com Mon Oct 7 15:37:47 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 07 Oct 2019 15:37:47 +0000 Subject: [njs] Aligning prototypes of njs_grisu2() and njs_grisu2_prec(). Message-ID: details: https://hg.nginx.org/njs/rev/d6ba4bffddef branches: changeset: 1173:d6ba4bffddef user: Dmitry Volyntsev date: Mon Oct 07 18:11:19 2019 +0300 description: Aligning prototypes of njs_grisu2() and njs_grisu2_prec(). diffstat: src/njs_dtoa.c | 64 ++++++++++++++++++++++++++++++++------------------------- 1 files changed, 36 insertions(+), 28 deletions(-) diffs (172 lines): diff -r 5c71fd61dc15 -r d6ba4bffddef src/njs_dtoa.c --- a/src/njs_dtoa.c Fri Oct 04 19:46:35 2019 +0300 +++ b/src/njs_dtoa.c Mon Oct 07 18:11:19 2019 +0300 @@ -318,15 +318,17 @@ njs_diyfp_normalize_boundaries(njs_diyfp * of IEEE doubles. For remaining 0.2% bignum algorithm like Dragon4 is requred. */ njs_inline size_t -njs_grisu2(double value, char *start, int *dec_exp) +njs_grisu2(double value, char *start, int *point) { + int dec_exp; + size_t length; njs_diyfp_t v, low, high, ten_mk, scaled_v, scaled_low, scaled_high; v = njs_d2diyfp(value); njs_diyfp_normalize_boundaries(v, &low, &high); - ten_mk = njs_cached_power_bin(high.exp, dec_exp); + ten_mk = njs_cached_power_bin(high.exp, &dec_exp); scaled_v = njs_diyfp_mul(njs_diyfp_normalize(v), ten_mk); scaled_low = njs_diyfp_mul(low, ten_mk); @@ -335,9 +337,13 @@ njs_grisu2(double value, char *start, in scaled_low.significand++; scaled_high.significand--; - return njs_digit_gen(scaled_v, scaled_high, + length = njs_digit_gen(scaled_v, scaled_high, scaled_high.significand - scaled_low.significand, - start, dec_exp); + start, &dec_exp); + + *point = length + dec_exp; + + return length; } @@ -397,40 +403,39 @@ njs_write_exponent(int exp, char *start) njs_inline size_t -njs_dtoa_format(char *start, size_t len, int dec_exp) +njs_dtoa_format(char *start, size_t len, int point) { - int kk, offset, length; + int offset, length; size_t size; - /* 10^(kk-1) <= v < 10^kk */ + length = (int) len; - length = (int) len; - kk = length + dec_exp; - - if (length <= kk && kk <= 21) { + if (length <= point && point <= 21) { /* 1234e7 -> 12340000000 */ - if (kk - length > 0) { - njs_memset(&start[length], '0', kk - length); + if (point - length > 0) { + njs_memset(&start[length], '0', point - length); } - return kk; + return point; + } - } else if (0 < kk && kk <= 21) { + if (0 < point && point <= 21) { /* 1234e-2 -> 12.34 */ - memmove(&start[kk + 1], &start[kk], length - kk); - start[kk] = '.'; + memmove(&start[point + 1], &start[point], length - point); + start[point] = '.'; return length + 1; + } - } else if (-6 < kk && kk <= 0) { + if (-6 < point && point <= 0) { /* 1234e-6 -> 0.001234 */ - offset = 2 - kk; + offset = 2 - point; memmove(&start[offset], start, length); start[0] = '0'; @@ -441,26 +446,26 @@ njs_dtoa_format(char *start, size_t len, } return length + offset; + } - } else if (length == 1) { + /* 1234e30 -> 1.234e33 */ + + if (length == 1) { /* 1e30 */ start[1] = 'e'; - size = njs_write_exponent(kk - 1, &start[2]); + size = njs_write_exponent(point - 1, &start[2]); return size + 2; - } - /* 1234e30 -> 1.234e33 */ - memmove(&start[2], &start[1], length - 1); start[1] = '.'; start[length + 1] = 'e'; - size = njs_write_exponent(kk - 1, &start[length + 2]); + size = njs_write_exponent(point - 1, &start[length + 2]); return size + length + 2; } @@ -496,6 +501,7 @@ njs_dtoa_prec_format(char *start, size_t /* Fixed notation. */ if (point <= 0) { + /* 1234e-2 => 0.001234000 */ memmove(&start[2 + (-point)], start, len); @@ -512,6 +518,7 @@ njs_dtoa_prec_format(char *start, size_t } if (point >= (int) len) { + /* TODO: (2**96).toPrecision(45) not enough precision, BigInt needed. */ njs_memset(&start[len], '0', point - len); @@ -523,6 +530,7 @@ njs_dtoa_prec_format(char *start, size_t } } else if (point < (int) prec) { + /* 123456 -> 123.45600 */ m = njs_min((int) len, point); @@ -541,7 +549,7 @@ njs_dtoa_prec_format(char *start, size_t size_t njs_dtoa(double value, char *start) { - int dec_exp, minus; + int point, minus; char *p; size_t length; @@ -562,9 +570,9 @@ njs_dtoa(double value, char *start) minus = 1; } - length = njs_grisu2(value, p, &dec_exp); + length = njs_grisu2(value, p, &point); - return njs_dtoa_format(p, length, dec_exp) + minus; + return njs_dtoa_format(p, length, point) + minus; } From xeioex at nginx.com Mon Oct 7 15:37:47 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 07 Oct 2019 15:37:47 +0000 Subject: [njs] Added Number.prototype.toExponential(). Message-ID: details: https://hg.nginx.org/njs/rev/c9061ff75070 branches: changeset: 1174:c9061ff75070 user: Dmitry Volyntsev date: Mon Oct 07 18:16:47 2019 +0300 description: Added Number.prototype.toExponential(). diffstat: src/njs_dtoa.c | 80 +++++++++++++++++++++++++++++++++++++---------- src/njs_dtoa.h | 2 + src/njs_number.c | 55 +++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 48 ++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 17 deletions(-) diffs (242 lines): diff -r d6ba4bffddef -r c9061ff75070 src/njs_dtoa.c --- a/src/njs_dtoa.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_dtoa.c Mon Oct 07 18:16:47 2019 +0300 @@ -472,30 +472,36 @@ njs_dtoa_format(char *start, size_t len, njs_inline size_t +njs_dtoa_exp_format(char *start, int exponent, size_t prec, size_t len) +{ + char *p; + + p = &start[len]; + if (prec != 1) { + memmove(&start[2], &start[1], len - 1); + start[1] = '.'; + p++; + } + + njs_memset(p, '0', prec - len); + p += prec - len; + + *p++ = 'e'; + + return prec + 1 + (prec != 1) + njs_write_exponent(exponent, p); +} + + +njs_inline size_t njs_dtoa_prec_format(char *start, size_t prec, size_t len, int point) { int exponent; - char *p; - size_t m, rest, size; + size_t m, rest; exponent = point - 1; if (exponent < -6 || exponent >= (int) prec) { - p = &start[len]; - if (prec != 1) { - memmove(&start[2], &start[1], len - 1); - start[1] = '.'; - p++; - } - - njs_memset(p, '0', prec - len); - p += prec - len; - - *p++ = 'e'; - - size = njs_write_exponent(exponent, p); - - return prec + 1 + (prec != 1) + size; + return njs_dtoa_exp_format(start, exponent, prec, len); } /* Fixed notation. */ @@ -609,3 +615,43 @@ njs_dtoa_precision(double value, char *s return njs_dtoa_prec_format(p, prec, length, point) + minus; } + + +size_t +njs_dtoa_exponential(double value, char *start, njs_int_t frac) +{ + int point, minus; + char *p; + size_t length; + + /* Not handling NaN and inf. */ + + p = start; + minus = 0; + + if (value != 0) { + if (value < 0) { + *p++ = '-'; + value = -value; + minus = 1; + } + + if (frac == -1) { + length = njs_grisu2(value, p, &point); + + } else { + length = njs_grisu2_prec(value, p, frac + 1, &point); + } + + } else { + start[0] = '0'; + length = 1; + point = 1; + } + + if (frac == -1) { + frac = length - 1; + } + + return njs_dtoa_exp_format(p, point - 1, frac + 1, length) + minus; +} diff -r d6ba4bffddef -r c9061ff75070 src/njs_dtoa.h --- a/src/njs_dtoa.h Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_dtoa.h Mon Oct 07 18:16:47 2019 +0300 @@ -9,5 +9,7 @@ NJS_EXPORT size_t njs_dtoa(double value, char *start); NJS_EXPORT size_t njs_dtoa_precision(double value, char *start, size_t prec); +NJS_EXPORT size_t njs_dtoa_exponential(double value, char *start, + njs_int_t frac); #endif /* _NJS_DTOA_H_INCLUDED_ */ diff -r d6ba4bffddef -r c9061ff75070 src/njs_number.c --- a/src/njs_number.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_number.c Mon Oct 07 18:16:47 2019 +0300 @@ -684,6 +684,52 @@ njs_number_prototype_to_precision(njs_vm } +static njs_int_t +njs_number_prototype_to_exponential(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + double number; + size_t size; + int32_t frac; + njs_value_t *value; + u_char buf[128]; + + value = &args[0]; + + if (value->type != NJS_NUMBER) { + if (value->type == NJS_OBJECT_NUMBER) { + value = njs_object_value(value); + + } else { + njs_type_error(vm, "unexpected value type:%s", + njs_type_string(value->type)); + return NJS_ERROR; + } + } + + number = njs_number(value); + + if (njs_slow_path(isnan(number) || isinf(number))) { + return njs_number_to_string(vm, &vm->retval, value); + } + + if (njs_is_defined(njs_arg(args, nargs, 1))) { + frac = njs_primitive_value_to_integer(njs_argument(args, 1)); + if (njs_slow_path(frac < 0 || frac > 100)) { + njs_range_error(vm, "digits argument must be between 0 and 100"); + return NJS_ERROR; + } + + } else { + frac = -1; + } + + size = njs_dtoa_exponential(number, (char *) buf, frac); + + return njs_string_new(vm, &vm->retval, buf, size, size); +} + + /* * The radix equal to 2 produces the longest value for a number. */ @@ -858,6 +904,15 @@ static const njs_object_prop_t njs_numb .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("toExponential"), + .value = njs_native_function(njs_number_prototype_to_exponential, + NJS_SKIP_ARG, NJS_INTEGER_ARG), + .writable = 1, + .configurable = 1, + }, }; diff -r d6ba4bffddef -r c9061ff75070 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/test/njs_unit_test.c Mon Oct 07 18:16:47 2019 +0300 @@ -628,6 +628,54 @@ static njs_unit_test_t njs_test[] = { njs_str("(0).toFixed(101)"), njs_str("RangeError: digits argument must be between 0 and 100") }, + /* Number.prototype.toExponential(frac) method. */ + + { njs_str("Array(3).fill().map((n, i) => i + 1).map((v)=>(0).toExponential(v))"), + njs_str("0.0e+0,0.00e+0,0.000e+0") }, + + { njs_str("Array(6).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential(5))"), + njs_str("-6.66667e-1,1.33333e+0,-2.00000e+0,2.66667e+0,-3.33333e+0,4.00000e+0") }, + + { njs_str("Array(5).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential())"), + njs_str("-6.666666666666666e-1,1.3333333333333333e+0,-2e+0,2.6666666666666667e+0,-3.3333333333333337e+0") }, + +#ifndef NJS_SUNC + { njs_str("4.94065645841246544176568792868e-324.toExponential()"), + njs_str("5e-324") }, + + { njs_str("4.94065645841246544176568792868e-324.toExponential(10)"), + njs_str("4.9406564584e-324") }, +#endif + + { njs_str("1.7976931348623157e+308.toExponential()"), + njs_str("1.7976931348623157e+308") }, + +#if 0 /* FIXME: bignum support is requred to support prec >= 20 */ + { njs_str("(1/7).toExponential(100)"), + njs_str("1.4285714285714284921269268124888185411691665649414062500000000000000000000000000000000000000000000000e-1") }, +#endif + + { njs_str("var v = 1.7976931348623157e+308; Number(v.toExponential()) == v"), + njs_str("true") }, + + { njs_str("(123).toExponential(-1)"), + njs_str("RangeError: digits argument must be between 0 and 100") }, + + { njs_str("(123).toExponential(2.4)"), + njs_str("1.23e+2") }, + + { njs_str("(123).toExponential(101)"), + njs_str("RangeError: digits argument must be between 0 and 100") }, + + { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential())"), + njs_str("Infinity,-Infinity,NaN") }, + + { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential(1000))"), + njs_str("Infinity,-Infinity,NaN") }, + + { njs_str("Number.prototype.toExponential.call('12')"), + njs_str("TypeError: unexpected value type:string") }, + /* An object "valueOf/toString" methods. */ { njs_str("var a = { valueOf: function() { return 1 } }; +a"), From alexander.borisov at nginx.com Tue Oct 8 05:16:53 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 08 Oct 2019 05:16:53 +0000 Subject: [njs] Fixed Array.prototype.map() for a object with nonexistent values. Message-ID: details: https://hg.nginx.org/njs/rev/b63351157159 branches: changeset: 1175:b63351157159 user: Alexander Borisov date: Mon Sep 30 11:41:00 2019 +0300 description: Fixed Array.prototype.map() for a object with nonexistent values. Previously nonexistent values in the object were skipped and not added to the result. diffstat: src/njs_array.c | 104 +++++++++++++++++++++------------------------- src/test/njs_unit_test.c | 10 ++++ 2 files changed, 57 insertions(+), 57 deletions(-) diffs (198 lines): diff -r c9061ff75070 -r b63351157159 src/njs_array.c --- a/src/njs_array.c Mon Oct 07 18:16:47 2019 +0300 +++ b/src/njs_array.c Mon Sep 30 11:41:00 2019 +0300 @@ -1300,6 +1300,34 @@ njs_object_indexes(njs_vm_t *vm, njs_val njs_inline njs_int_t +njs_array_object_handler(njs_vm_t *vm, njs_array_iterator_handler_t handler, + njs_array_iterator_args_t *args, njs_value_t *key, uint32_t i) +{ + njs_int_t ret; + njs_value_t prop, *entry; + + ret = njs_value_property(vm, args->value, key, &prop); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + entry = (ret == NJS_OK) ? &prop : njs_value_arg(&njs_value_invalid); + + ret = handler(vm, args, entry, i); + + if (njs_slow_path(ret != NJS_OK)) { + if (ret > 0) { + return NJS_DECLINED; + } + + return NJS_ERROR; + } + + return ret; +} + + +njs_inline njs_int_t njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args, njs_array_iterator_handler_t handler) { @@ -1307,7 +1335,7 @@ njs_array_iterator(njs_vm_t *vm, njs_arr uint32_t length, i, from, to; njs_int_t ret; njs_array_t *keys; - njs_value_t *entry, *value, character, index, string_obj, prop; + njs_value_t *entry, *value, character, index, string_obj; njs_object_t *object; const u_char *p, *end, *pos; njs_string_prop_t string_prop; @@ -1421,21 +1449,11 @@ process_object: continue; } - ret = njs_value_property(vm, value, &keys->start[i], &prop); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_array_object_handler(vm, handler, args, &keys->start[i], + i); + if (njs_slow_path(ret != NJS_OK)) { return ret; } - - if (ret != NJS_DECLINED) { - ret = handler(vm, args, &prop, i); - if (njs_slow_path(ret != NJS_OK)) { - if (ret > 0) { - return NJS_DECLINED; - } - - return NJS_ERROR; - } - } } return NJS_OK; @@ -1444,21 +1462,10 @@ process_object: for (i = from; i < to; i++) { njs_uint32_to_string(&index, i); - ret = njs_value_property(vm, value, &index, &prop); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_array_object_handler(vm, handler, args, &index, i); + if (njs_slow_path(ret != NJS_OK)) { return ret; } - - if (ret != NJS_DECLINED) { - ret = handler(vm, args, &prop, i); - if (njs_slow_path(ret != NJS_OK)) { - if (ret > 0) { - return NJS_DECLINED; - } - - return NJS_ERROR; - } - } } return NJS_OK; @@ -1473,7 +1480,7 @@ njs_array_reverse_iterator(njs_vm_t *vm, uint32_t i, from, to, length; njs_int_t ret; njs_array_t *keys; - njs_value_t *entry, *value, character, index, string_obj, prop; + njs_value_t *entry, *value, character, index, string_obj; njs_object_t *object; const u_char *p, *end, *pos; njs_string_prop_t string_prop; @@ -1597,21 +1604,11 @@ process_object: continue; } - ret = njs_value_property(vm, value, &keys->start[i], &prop); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_array_object_handler(vm, handler, args, &keys->start[i], + idx); + if (njs_slow_path(ret != NJS_OK)) { return ret; } - - if (ret != NJS_DECLINED) { - ret = handler(vm, args, &prop, idx); - if (njs_slow_path(ret != NJS_OK)) { - if (ret > 0) { - return NJS_DECLINED; - } - - return NJS_ERROR; - } - } } return NJS_OK; @@ -1622,21 +1619,10 @@ process_object: while (i-- > to) { njs_uint32_to_string(&index, i); - ret = njs_value_property(vm, value, &index, &prop); - if (njs_slow_path(ret == NJS_ERROR)) { + ret = njs_array_object_handler(vm, handler, args, &index, i); + if (njs_slow_path(ret != NJS_OK)) { return ret; } - - if (ret != NJS_DECLINED) { - ret = handler(vm, args, &prop, i); - if (njs_slow_path(ret != NJS_OK)) { - if (ret > 0) { - return NJS_DECLINED; - } - - return NJS_ERROR; - } - } } return NJS_OK; @@ -2457,6 +2443,12 @@ njs_array_prototype_map(njs_vm_t *vm, nj return NJS_ERROR; } + if (length > NJS_ARRAY_LARGE_OBJECT_LENGTH) { + for (i = 0; i < length; i++) { + njs_set_invalid(&iargs.array->start[i]); + } + } + if (length > 0) { iargs.from = 0; iargs.to = length; @@ -2466,9 +2458,7 @@ njs_array_prototype_map(njs_vm_t *vm, nj return ret; } - if (njs_is_array(&args[0]) - && njs_object_hash_is_empty(&args[0])) - { + if (njs_is_array(&args[0]) && njs_object_hash_is_empty(&args[0])) { array = iargs.array; for (i = njs_array_len(&args[0]); i < length; i++) { diff -r c9061ff75070 -r b63351157159 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Oct 07 18:16:47 2019 +0300 +++ b/src/test/njs_unit_test.c Mon Sep 30 11:41:00 2019 +0300 @@ -4799,6 +4799,16 @@ static njs_unit_test_t njs_test[] = { njs_str("Array.prototype.map.call('abcdef', (val, idx, obj) => {return val === 100})"), njs_str("false,false,false,false,false,false") }, + { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}" + "var obj = {2: 2, length: 10};" + "var res = Array.prototype.map.call(obj, callbackfn); typeof res[7]"), + njs_str("undefined") }, + + { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}" + "var obj = {2: 2, length: 9000};" + "var res = Array.prototype.map.call(obj, callbackfn); typeof res[8000]"), + njs_str("undefined") }, + { njs_str("var a = [];" "a.reduce(function(p, v, i, a) { return p + v })"), njs_str("TypeError: Reduce of empty object with no initial value") }, From xeioex at nginx.com Tue Oct 8 12:57:13 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 08 Oct 2019 12:57:13 +0000 Subject: [njs] Fixing Coverity warnings related to close() (CID 1444170). Message-ID: details: https://hg.nginx.org/njs/rev/9f1ba171d81e branches: changeset: 1176:9f1ba171d81e user: Dmitry Volyntsev date: Tue Oct 08 15:56:58 2019 +0300 description: Fixing Coverity warnings related to close() (CID 1444170). diffstat: src/njs_module.c | 2 +- src/njs_shell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r b63351157159 -r 9f1ba171d81e src/njs_module.c --- a/src/njs_module.c Mon Sep 30 11:41:00 2019 +0300 +++ b/src/njs_module.c Tue Oct 08 15:56:58 2019 +0300 @@ -139,7 +139,7 @@ njs_parser_module(njs_vm_t *vm, njs_pars ret = njs_module_read(vm, info.fd, &text); - close(info.fd); + (void) close(info.fd); if (njs_slow_path(ret != NJS_OK)) { njs_internal_error(vm, "while reading \"%V\" module", &name); diff -r b63351157159 -r 9f1ba171d81e src/njs_shell.c --- a/src/njs_shell.c Mon Sep 30 11:41:00 2019 +0300 +++ b/src/njs_shell.c Tue Oct 08 15:56:58 2019 +0300 @@ -633,7 +633,7 @@ done: close_fd: if (fd != STDIN_FILENO) { - close(fd); + (void) close(fd); } return ret; From ru at nginx.com Tue Oct 8 18:57:52 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 08 Oct 2019 18:57:52 +0000 Subject: [nginx] Improved detection of broken percent encoding in URI. Message-ID: details: https://hg.nginx.org/nginx/rev/5a3426683251 branches: changeset: 7577:5a3426683251 user: Ruslan Ermilov date: Tue Oct 08 21:56:14 2019 +0300 description: Improved detection of broken percent encoding in URI. diffstat: src/http/ngx_http_parse.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff -r 7fdcf308e0f0 -r 5a3426683251 src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c Mon Sep 30 16:39:20 2019 +0300 +++ b/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 @@ -1561,6 +1561,10 @@ ngx_http_parse_complex_uri(ngx_http_requ } } + if (state == sw_quoted || state == sw_quoted_second) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + done: r->uri.len = u - r->uri.data; From ru at nginx.com Tue Oct 8 18:57:53 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 08 Oct 2019 18:57:53 +0000 Subject: [nginx] The "/." and "/.." at the end of URI should be normalized. Message-ID: details: https://hg.nginx.org/nginx/rev/79bcbe7cd3f2 branches: changeset: 7578:79bcbe7cd3f2 user: Ruslan Ermilov date: Tue Oct 08 21:56:14 2019 +0300 description: The "/." and "/.." at the end of URI should be normalized. diffstat: src/http/ngx_http_parse.c | 38 ++++++++++++++++++++++++++++++++------ 1 files changed, 32 insertions(+), 6 deletions(-) diffs (77 lines): diff -r 5a3426683251 -r 79bcbe7cd3f2 src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 +++ b/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 @@ -1437,9 +1437,11 @@ ngx_http_parse_complex_uri(ngx_http_requ state = sw_quoted; break; case '?': + u--; r->args_start = p; goto args; case '#': + u--; goto done; case '+': r->plus_in_uri = 1; @@ -1467,7 +1469,8 @@ ngx_http_parse_complex_uri(ngx_http_requ case '\\': #endif case '/': - state = sw_slash; + case '?': + case '#': u -= 5; for ( ;; ) { if (u < r->uri.data) { @@ -1479,16 +1482,19 @@ ngx_http_parse_complex_uri(ngx_http_requ } u--; } + if (ch == '?') { + r->args_start = p; + goto args; + } + if (ch == '#') { + goto done; + } + state = sw_slash; break; case '%': quoted_state = state; state = sw_quoted; break; - case '?': - r->args_start = p; - goto args; - case '#': - goto done; case '+': r->plus_in_uri = 1; /* fall through */ @@ -1565,6 +1571,26 @@ ngx_http_parse_complex_uri(ngx_http_requ return NGX_HTTP_PARSE_INVALID_REQUEST; } + if (state == sw_dot) { + u--; + + } else if (state == sw_dot_dot) { + u -= 5; + + for ( ;; ) { + if (u < r->uri.data) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + + if (*u == '/') { + u++; + break; + } + + u--; + } + } + done: r->uri.len = u - r->uri.data; From ru at nginx.com Tue Oct 8 18:57:55 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 08 Oct 2019 18:57:55 +0000 Subject: [nginx] Fixed URI normalization with merge_slashes switched off. Message-ID: details: https://hg.nginx.org/nginx/rev/6208c5418c88 branches: changeset: 7579:6208c5418c88 user: Maxim Dounin date: Tue Oct 08 21:56:14 2019 +0300 description: Fixed URI normalization with merge_slashes switched off. Previously, "/foo///../bar" was normalized into "/foo/bar" instead of "/foo//bar". diffstat: src/http/ngx_http_parse.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff -r 79bcbe7cd3f2 -r 6208c5418c88 src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 +++ b/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 @@ -1471,7 +1471,7 @@ ngx_http_parse_complex_uri(ngx_http_requ case '/': case '?': case '#': - u -= 5; + u -= 4; for ( ;; ) { if (u < r->uri.data) { return NGX_HTTP_PARSE_INVALID_REQUEST; @@ -1575,7 +1575,7 @@ ngx_http_parse_complex_uri(ngx_http_requ u--; } else if (state == sw_dot_dot) { - u -= 5; + u -= 4; for ( ;; ) { if (u < r->uri.data) { From alexander.borisov at nginx.com Wed Oct 9 15:56:20 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 09 Oct 2019 15:56:20 +0000 Subject: [njs] Fixed Array.prototype.pop() and shift() for sparse objects. Message-ID: details: https://hg.nginx.org/njs/rev/fa75ca7ed851 branches: changeset: 1178:fa75ca7ed851 user: Alexander Borisov date: Wed Oct 09 18:54:57 2019 +0300 description: Fixed Array.prototype.pop() and shift() for sparse objects. This closes #233 issue on GitHub. diffstat: src/njs_array.c | 4 ++-- src/test/njs_unit_test.c | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diffs (50 lines): diff -r 6ed84cda7426 -r fa75ca7ed851 src/njs_array.c --- a/src/njs_array.c Wed Oct 09 18:54:54 2019 +0300 +++ b/src/njs_array.c Wed Oct 09 18:54:57 2019 +0300 @@ -694,7 +694,7 @@ njs_array_prototype_pop(njs_vm_t *vm, nj njs_uint32_to_string(&index, --length); ret = njs_value_property_delete(vm, value, &index, &vm->retval); - if (njs_slow_path(ret != NJS_OK)) { + if (njs_slow_path(ret == NJS_ERROR)) { return ret; } } @@ -900,7 +900,7 @@ njs_array_prototype_shift(njs_vm_t *vm, njs_uint32_to_string(&index, 0); ret = njs_value_property_delete(vm, value, &index, &vm->retval); - if (njs_slow_path(ret != NJS_OK)) { + if (njs_slow_path(ret == NJS_ERROR)) { return ret; } diff -r 6ed84cda7426 -r fa75ca7ed851 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 09 18:54:54 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 09 18:54:57 2019 +0300 @@ -4093,6 +4093,12 @@ static njs_unit_test_t njs_test[] = "catch (e) {i += '; ' + e} i"), njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") }, + { njs_str("Array.prototype.pop.call({ length: 3 })"), + njs_str("undefined") }, + + { njs_str("var o = { length: 3 }; Array.prototype.pop.call(o); o.length"), + njs_str("2") }, + { njs_str("Array.prototype.shift()"), njs_str("undefined") }, @@ -4200,6 +4206,12 @@ static njs_unit_test_t njs_test[] = { njs_str("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"), njs_str("1") }, + { njs_str("Array.prototype.shift.call({ length: 3 })"), + njs_str("undefined") }, + + { njs_str("var o = { length: 3 }; Array.prototype.shift.call(o); o.length"), + njs_str("2") }, + { njs_str("var a = []; a.splice()"), njs_str("") }, From alexander.borisov at nginx.com Wed Oct 9 15:56:20 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 09 Oct 2019 15:56:20 +0000 Subject: [njs] Fixed Array functions according to specification. Message-ID: details: https://hg.nginx.org/njs/rev/6ed84cda7426 branches: changeset: 1177:6ed84cda7426 user: Alexander Borisov date: Wed Oct 09 18:54:54 2019 +0300 description: Fixed Array functions according to specification. Length property should be queried before checking arguments for validity. ?ffected functions: every, filter, find, findIndex, forEach, map, reduce, reduceRight, some. This closes #228 issue on GitHub. diffstat: src/njs_array.c | 194 ++++++++++++++++++---------------------------- src/test/njs_unit_test.c | 81 +++++++++++++++++++ 2 files changed, 159 insertions(+), 116 deletions(-) diffs (518 lines): diff -r 9f1ba171d81e -r 6ed84cda7426 src/njs_array.c --- a/src/njs_array.c Tue Oct 08 15:56:58 2019 +0300 +++ b/src/njs_array.c Wed Oct 09 18:54:54 2019 +0300 @@ -2014,6 +2014,41 @@ njs_array_iterator_call(njs_vm_t *vm, nj } +njs_inline njs_int_t +njs_array_validate_args(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_array_iterator_args_t *iargs) +{ + njs_int_t ret; + + if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { + goto failed; + } + + iargs->value = njs_argument(args, 0); + + ret = njs_value_length(vm, iargs->value, &iargs->to); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) { + goto failed; + } + + iargs->from = 0; + iargs->function = njs_function(njs_argument(args, 1)); + iargs->argument = njs_arg(args, nargs, 2); + + return NJS_OK; + +failed: + + njs_type_error(vm, "unexpected iterator arguments"); + + return NJS_ERROR; +} + + static njs_int_t njs_array_handler_for_each(njs_vm_t *vm, njs_array_iterator_args_t *args, njs_value_t *entry, uint32_t n) @@ -2033,20 +2068,7 @@ njs_array_prototype_for_each(njs_vm_t *v njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2092,20 +2114,7 @@ njs_array_prototype_some(njs_vm_t *vm, n njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2153,20 +2162,7 @@ njs_array_prototype_every(njs_vm_t *vm, njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2219,20 +2215,7 @@ njs_array_prototype_filter(njs_vm_t *vm, njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2289,20 +2272,7 @@ njs_array_prototype_find(njs_vm_t *vm, n njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2356,20 +2326,7 @@ njs_array_prototype_find_index(njs_vm_t njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; - } - - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); - - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); + ret = njs_array_validate_args(vm, args, nargs, &iargs); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2422,22 +2379,21 @@ njs_array_prototype_map(njs_vm_t *vm, nj njs_array_t *array; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { + goto unexpected_args; } iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = njs_arg(args, nargs, 2); ret = njs_value_length(vm, iargs.value, &length); if (njs_slow_path(ret != NJS_OK)) { return ret; } + if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) { + goto unexpected_args; + } + iargs.array = njs_array_alloc(vm, length, 0); if (njs_slow_path(iargs.array == NULL)) { return NJS_ERROR; @@ -2453,6 +2409,9 @@ njs_array_prototype_map(njs_vm_t *vm, nj iargs.from = 0; iargs.to = length; + iargs.function = njs_function(njs_argument(args, 1)); + iargs.argument = njs_arg(args, nargs, 2); + ret = njs_array_iterator(vm, &iargs, njs_array_handler_map); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -2470,6 +2429,12 @@ njs_array_prototype_map(njs_vm_t *vm, nj njs_set_array(&vm->retval, iargs.array); return NJS_OK; + +unexpected_args: + + njs_type_error(vm, "unexpected iterator arguments"); + + return NJS_ERROR; } @@ -2522,30 +2487,19 @@ njs_array_prototype_reduce(njs_vm_t *vm, njs_value_t accumulator; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + ret = njs_array_validate_args(vm, args, nargs, &iargs); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } njs_set_invalid(&accumulator); if (nargs > 2) { - accumulator = *njs_argument(args, 2); + accumulator = *iargs.argument; } - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); iargs.argument = &accumulator; - iargs.from = 0; - - ret = njs_value_length(vm, iargs.value, &iargs.to); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - ret = njs_array_iterator(vm, &iargs, njs_array_handler_reduce); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -2570,25 +2524,27 @@ njs_array_prototype_reduce_right(njs_vm_ njs_value_t accumulator; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0)) - || !njs_is_function(njs_arg(args, nargs, 1))) - { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { + goto unexpected_args; } - njs_set_invalid(&accumulator); - iargs.value = njs_argument(args, 0); - iargs.function = njs_function(&args[1]); - iargs.argument = &accumulator; - iargs.to = 0; ret = njs_value_length(vm, iargs.value, &iargs.from); if (njs_slow_path(ret != NJS_OK)) { return ret; } + if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) { + goto unexpected_args; + } + + njs_set_invalid(&accumulator); + + iargs.to = 0; + iargs.function = njs_function(njs_argument(args, 1)); + iargs.argument = &accumulator; + if (nargs > 2) { accumulator = *njs_argument(args, 2); } @@ -2623,6 +2579,12 @@ failed: njs_type_error(vm, "Reduce of empty object with no initial value"); return NJS_ERROR; + +unexpected_args: + + njs_type_error(vm, "unexpected iterator arguments"); + + return NJS_ERROR; } diff -r 9f1ba171d81e -r 6ed84cda7426 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Oct 08 15:56:58 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 09 18:54:54 2019 +0300 @@ -4088,6 +4088,11 @@ static njs_unit_test_t njs_test[] = { njs_str("var o = Object.freeze({0: 0, 1: 1, length: 2}); Array.prototype.pop.call(o)"), njs_str("TypeError: Cannot delete property \"1\" of object") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.pop.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") }, + { njs_str("Array.prototype.shift()"), njs_str("undefined") }, @@ -4129,6 +4134,11 @@ static njs_unit_test_t njs_test[] = "Array.prototype.forEach.call(x, (v) => a.push(v)); a"), njs_str("a,b,c,x,y,z,123") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.push.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") }, + { njs_str("var a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"), njs_str("1 2 2") }, @@ -4136,6 +4146,11 @@ static njs_unit_test_t njs_test[] = "Array.prototype.shift.call(x) +' '+ x[0] +' '+ x.length"), njs_str("x y 2") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.shift.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") }, + { njs_str("var a = [1,2], len = a.unshift(3);" "len +' '+ a +' '+ a.shift()"), njs_str("3 3,1,2 3") }, @@ -4177,6 +4192,11 @@ static njs_unit_test_t njs_test[] = "Array.prototype.forEach.call(obj, (v) => a.push(v)); a"), njs_str("a,b,c,x,y,z")}, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.unshift.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") }, + { njs_str("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"), njs_str("1") }, @@ -4257,6 +4277,10 @@ static njs_unit_test_t njs_test[] = "Array.prototype.indexOf.call(o, 'd')"), njs_str("3") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "Array.prototype.indexOf.call(o); i"), + njs_str("1") }, + { njs_str("[].lastIndexOf(1, -1)"), njs_str("-1") }, @@ -4337,6 +4361,10 @@ static njs_unit_test_t njs_test[] = "Array.prototype.lastIndexOf.call(obj, 'y');"), njs_str("10000001")}, + { njs_str("var i = 0; var o = {get length() {i++}};" + "Array.prototype.lastIndexOf.call(o); i"), + njs_str("1") }, + { njs_str("[1,2,3,4].includes()"), njs_str("false") }, @@ -4437,6 +4465,11 @@ static njs_unit_test_t njs_test[] = "Array.prototype.forEach.call(s, function (a, b, c) {t = typeof c;}); [t, typeof s];"), njs_str("object,string") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.forEach.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.some(function(v, i, a) { return v > 1 })"), njs_str("false") }, @@ -4467,6 +4500,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.some.call(o, function(v, i, a) { return v === 'd' }); r"), njs_str("true") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.some.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.every(function(v, i, a) { return v > 1 })"), njs_str("true") }, @@ -4491,6 +4529,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.every.call(o, function(el, i, arr) {return el == 'c'}); r"), njs_str("true") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.every.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var o = {0: 'x', 1: 'y', 2: 'z'};" "Object.defineProperty(o, 'length', {get: () => 4});" "Object.defineProperty(o, '3', {get: () => 'a'});" @@ -4604,6 +4647,10 @@ static njs_unit_test_t njs_test[] = njs_str("RangeError: Maximum call stack size exceeded") }, #endif + { njs_str("var i = 0; var o = {get length() {i++}};" + "Array.prototype.fill.call(o); i"), + njs_str("1") }, + { njs_str("var a = [];" "a.filter(function(v, i, a) { return v > 1 })"), njs_str("") }, @@ -4646,6 +4693,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.filter.call(o, function(el, i, arr) { return el == 'c' }); r"), njs_str("c,c") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.filter.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.find(function(v, i, a) { return v > 1 })"), njs_str("undefined") }, @@ -4703,6 +4755,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.find.call(o, function(el, i, arr) { return el == 'd' }); r"), njs_str("d") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.find.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.findIndex(function(v, i, a) { return v > 1 })"), njs_str("-1") }, @@ -4757,6 +4814,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.findIndex.call(o, function(el, i, arr) { return el == 'd' }); r"), njs_str("3") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.findIndex.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.map(function(v, i, a) { return v + 1 })"), njs_str("") }, @@ -4809,6 +4871,11 @@ static njs_unit_test_t njs_test[] = "var res = Array.prototype.map.call(obj, callbackfn); typeof res[8000]"), njs_str("undefined") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.map.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.reduce(function(p, v, i, a) { return p + v })"), njs_str("TypeError: Reduce of empty object with no initial value") }, @@ -4862,6 +4929,11 @@ static njs_unit_test_t njs_test[] = "var r = Array.prototype.reduce.call(o, (a, b) => a + b); r"), njs_str("abcd") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.reduce.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = [];" "a.reduceRight(function(p, v, i, a) { return p + v })"), njs_str("TypeError: Reduce of empty object with no initial value") }, @@ -4910,6 +4982,11 @@ static njs_unit_test_t njs_test[] = "Array.prototype.reduceRight.call(o, (p, v) => p + v)"), njs_str("dcba") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "try {Array.prototype.reduceRight.call(o);}" + "catch (e) {i += '; ' + e} i"), + njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var a = ['1','2','3','4','5','6']; a.sort()"), njs_str("1,2,3,4,5,6") }, @@ -6053,6 +6130,10 @@ static njs_unit_test_t njs_test[] = { njs_str("'??? ??? ????????'.includes('?????', 9)"), njs_str("false") }, + { njs_str("var i = 0; var o = {get length() {i++}};" + "Array.prototype.includes.call(o); i"), + njs_str("1") }, + { njs_str("''.startsWith('')"), njs_str("true") }, From xeioex at nginx.com Thu Oct 10 17:54:28 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 10 Oct 2019 17:54:28 +0000 Subject: [njs] Fixed Date.UTC() according to specification. Message-ID: details: https://hg.nginx.org/njs/rev/78371ab5c449 branches: changeset: 1179:78371ab5c449 user: Dmitry Volyntsev date: Wed Oct 09 14:43:09 2019 +0300 description: Fixed Date.UTC() according to specification. This closes #235 issue on Github. diffstat: src/njs_date.c | 116 +++++++++++++++++++++++++++++++++++++++------- src/test/njs_unit_test.c | 50 ++++++++++++++++++++ 2 files changed, 147 insertions(+), 19 deletions(-) diffs (234 lines): diff -r fa75ca7ed851 -r 78371ab5c449 src/njs_date.c --- a/src/njs_date.c Wed Oct 09 18:54:57 2019 +0300 +++ b/src/njs_date.c Wed Oct 09 14:43:09 2019 +0300 @@ -44,7 +44,29 @@ static double njs_date_utc_time(struct t static const njs_value_t njs_string_invalid_date = njs_string("Invalid Date"); -static uint64_t +njs_inline int64_t +njs_mod(int64_t a, int64_t b) +{ + int64_t m; + + m = a % b; + + return m + (m < 0) * b; +} + + +njs_inline int64_t +njs_floor_div(int64_t a, int64_t b) +{ + int64_t m; + + m = a % b; + + return (a - (m + (m < 0) * b)) / b; +} + + +njs_inline uint64_t njs_gettime(void) { struct timeval tv; @@ -55,14 +77,71 @@ njs_gettime(void) } -static double +njs_inline double njs_timeclip(double time) { - if (isinf(time) || isnan(time) || fabs(time) > 8.64e15) { + if (time < -8.64e15 || time > 8.64e15) { return NAN; } - return njs_number_to_int64(time); + return trunc(time) + 0.0; +} + + +njs_inline int64_t +njs_make_time(int64_t h, int64_t min, int64_t s, int64_t milli) +{ + return ((h * 60 + min) * 60 + s) * 1000 + milli; +} + + +njs_inline int64_t +njs_days_in_year(int64_t y) +{ + return 365 + !(y % 4) - !(y % 100) + !(y % 400); +} + + +njs_inline int64_t +njs_days_from_year(int64_t y) +{ + return 365 * (y - 1970) + njs_floor_div(y - 1969, 4) + - njs_floor_div(y - 1901, 100) + njs_floor_div(y - 1601, 400); +} + + +njs_inline int64_t +njs_make_day(int64_t yr, int64_t month, int64_t date) +{ + int64_t i, ym, mn, md, days; + + static const int month_days[] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + + mn = njs_mod(month, 12); + ym = yr + (month - mn) / 12; + + days = njs_days_from_year(ym); + + for (i = 0; i < mn; i++) { + md = month_days[i]; + + if (i == 1) { + /* Leap day. */ + md += njs_days_in_year(ym) - 365; + } + + days += md; + } + + return days + date - 1; +} + + +njs_inline int64_t +njs_make_date(int64_t days, int64_t time) +{ + return days * 86400000 + time; } @@ -173,16 +252,19 @@ static njs_int_t njs_date_utc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + int64_t day, tm; double num, time; - struct tm tm; njs_int_t ret; njs_uint_t i, n; - int32_t values[8]; + int64_t values[8]; time = NAN; - if (nargs > 2) { - njs_memzero(values, 8 * sizeof(int32_t)); + if (nargs > 1) { + njs_memzero(values, 8 * sizeof(int64_t)); + + /* Day. */ + values[3] = 1; n = njs_min(8, nargs); @@ -196,7 +278,7 @@ njs_date_utc(njs_vm_t *vm, njs_value_t * num = njs_number(&args[i]); - if (isnan(num)) { + if (isnan(num) || isinf(num)) { goto done; } @@ -204,18 +286,14 @@ njs_date_utc(njs_vm_t *vm, njs_value_t * } /* Year. */ - if (values[1] > 99) { - values[1] -= 1900; + if (values[1] >= 0 && values[1] < 100) { + values[1] += 1900; } - tm.tm_year = values[1]; - tm.tm_mon = values[2]; - tm.tm_mday = values[3]; - tm.tm_hour = values[4]; - tm.tm_min = values[5]; - tm.tm_sec = values[6]; - - time = njs_timegm(&tm) * 1000 + values[7]; + day = njs_make_day(values[1], values[2], values[3]); + tm = njs_make_time(values[4], values[5], values[6], values[7]); + + time = njs_timeclip(njs_make_date(day, tm)); } done: diff -r fa75ca7ed851 -r 78371ab5c449 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 09 18:54:57 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 09 14:43:09 2019 +0300 @@ -11625,6 +11625,48 @@ static njs_unit_test_t njs_test[] = { njs_str("Date.UTC({valueOf:()=>2011}, 5, 24, 6, 0)"), njs_str("1308895200000") }, + { njs_str("Date.UTC()"), + njs_str("NaN") }, + + { njs_str("Date.UTC(Infinity)"), + njs_str("NaN") }, + + { njs_str("Date.UTC(Infinity, 0)"), + njs_str("NaN") }, + + { njs_str("Date.UTC(1970)"), + njs_str("0") }, + + { njs_str("Date.UTC(1968, 24)"), + njs_str("0") }, + + { njs_str("[-1,0,1,99,100].map(yr => Date.UTC(yr))"), + njs_str("-62198755200000,-2208988800000,-2177452800000,915148800000,-59011459200000") }, + + { njs_str("Date.UTC(1970.9, 0.9, 1.9, 0.9, 0.9, 0.9, 0.9)"), + njs_str("0") }, + + { njs_str("Date.UTC(-1970.9, -0.9, -0.9, -0.9, -0.9, -0.9, -0.9)"), + njs_str("-124334438400000") }, + + { njs_str("Date.UTC(275760, 8, 13, 0, 0, 0, 0)"), + njs_str("8640000000000000") }, + + { njs_str("Date.UTC(275760, 8, 13, 0, 0, 0, 1)"), + njs_str("NaN") }, + + { njs_str("Date.UTC(-271821, 3, 20, 0, 0, 0, 0)"), + njs_str("-8640000000000000") }, + + { njs_str("Date.UTC(-271821, 3, 20, 0, 0, 0, -1)"), + njs_str("NaN") }, + + { njs_str("Date.UTC(1970, 0)"), + njs_str("0") }, + + { njs_str("Date.UTC(1970, 0, 0)"), + njs_str("-86400000") }, + { njs_str("Date.parse()"), njs_str("NaN") }, @@ -11943,6 +11985,14 @@ static njs_unit_test_t njs_test[] = { njs_str("new Date(NaN)"), njs_str("Invalid Date") }, +#ifndef NJS_SUNC + { njs_str("new Date(-0).getTime()"), + njs_str("0") }, +#endif + + { njs_str("new Date(6.54321).valueOf()"), + njs_str("6") }, + { njs_str("[0].map(new Date().getDate)"), njs_str("TypeError: cannot convert undefined to date") }, From xeioex at nginx.com Thu Oct 10 17:54:28 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 10 Oct 2019 17:54:28 +0000 Subject: [njs] Fixed Date() constructor according to specification. Message-ID: details: https://hg.nginx.org/njs/rev/eb57c1e27495 branches: changeset: 1180:eb57c1e27495 user: Dmitry Volyntsev date: Thu Oct 10 20:54:03 2019 +0300 description: Fixed Date() constructor according to specification. diffstat: src/njs_date.c | 71 +++++++++++++++++++++++++++++------------------ src/test/njs_unit_test.c | 29 +++++++++++++++++++ 2 files changed, 73 insertions(+), 27 deletions(-) diffs (186 lines): diff -r 78371ab5c449 -r eb57c1e27495 src/njs_date.c --- a/src/njs_date.c Wed Oct 09 14:43:09 2019 +0300 +++ b/src/njs_date.c Thu Oct 10 20:54:03 2019 +0300 @@ -139,9 +139,32 @@ njs_make_day(int64_t yr, int64_t month, njs_inline int64_t -njs_make_date(int64_t days, int64_t time) +njs_tz_offset(int64_t time) { - return days * 86400000 + time; + time_t ti; + struct tm tm; + + time /= 1000; + + ti = time; + localtime_r(&ti, &tm); + + return -njs_timezone(&tm) / 60; +} + + +njs_inline int64_t +njs_make_date(int64_t days, int64_t time, njs_bool_t local) +{ + int64_t date; + + date = days * 86400000 + time; + + if (local) { + date += njs_tz_offset(date) * 60000; + } + + return date; } @@ -150,11 +173,11 @@ njs_date_constructor(njs_vm_t *vm, njs_v njs_index_t unused) { double num, time; - int64_t values[8]; + int64_t day, tm; njs_int_t ret; njs_uint_t i, n; njs_date_t *date; - struct tm tm; + int64_t values[8]; if (vm->top_frame->ctor) { @@ -182,9 +205,13 @@ njs_date_constructor(njs_vm_t *vm, njs_v } } else { + + time = NAN; + njs_memzero(values, 8 * sizeof(int64_t)); - /* Month. */ - values[2] = 1; + + /* Day. */ + values[3] = 1; n = njs_min(8, nargs); @@ -198,8 +225,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v num = njs_number(&args[i]); - if (isnan(num)) { - time = num; + if (isnan(num) || isinf(num)) { goto done; } @@ -207,19 +233,15 @@ njs_date_constructor(njs_vm_t *vm, njs_v } /* Year. */ - if (values[1] > 99) { - values[1] -= 1900; + if (values[1] >= 0 && values[1] < 100) { + values[1] += 1900; } - tm.tm_year = values[1]; - tm.tm_mon = values[2]; - tm.tm_mday = values[3]; - tm.tm_hour = values[4]; - tm.tm_min = values[5]; - tm.tm_sec = values[6]; - tm.tm_isdst = -1; - - time = (int64_t) mktime(&tm) * 1000 + values[7]; + day = njs_make_day(values[1], values[2], values[3]); + + tm = njs_make_time(values[4], values[5], values[6], values[7]); + + time = njs_make_date(day, tm, 1); } done: @@ -293,7 +315,7 @@ njs_date_utc(njs_vm_t *vm, njs_value_t * day = njs_make_day(values[1], values[2], values[3]); tm = njs_make_time(values[4], values[5], values[6], values[7]); - time = njs_timeclip(njs_make_date(day, tm)); + time = njs_timeclip(njs_make_date(day, tm, 0)); } done: @@ -1478,17 +1500,12 @@ static njs_int_t njs_date_prototype_get_timezone_offset(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - double value; - time_t clock; - struct tm tm; + double value; value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { - clock = value / 1000; - localtime_r(&clock, &tm); - - value = - njs_timezone(&tm) / 60; + value = njs_tz_offset(value); } njs_set_number(&vm->retval, value); diff -r 78371ab5c449 -r eb57c1e27495 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 09 14:43:09 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 10 20:54:03 2019 +0300 @@ -11606,6 +11606,11 @@ static njs_unit_test_t njs_test[] = "d.toISOString()"), njs_str("2011-06-24T18:45:12.625Z") }, + { njs_str("var d = new Date(1999, 9, 10, 10, 10, 10, 10);" + "var local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);" + "local.toISOString()"), + njs_str("1999-10-10T10:10:10.010Z") }, + #if 0 /* These tests fail on Solaris: gmtime_r() returns off by one day. */ @@ -11790,12 +11795,36 @@ static njs_unit_test_t njs_test[] = { njs_str("var n = Date.now(); n == new Date(n)"), njs_str("true") }, + { njs_str("var d = new Date(2011,0); d.getFullYear()"), + njs_str("2011") }, + + { njs_str("var d = new Date(2011, 0, 1, 0, 0, 0, -1); d.getFullYear()"), + njs_str("2010") }, + + { njs_str("var d = new Date(2011, 11, 31, 23, 59, 59, 999); d.getFullYear()"), + njs_str("2011") }, + + { njs_str("var d = new Date(2011, 11, 31, 23, 59, 59, 1000); d.getFullYear()"), + njs_str("2012") }, + { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getFullYear()"), njs_str("2011") }, { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCFullYear()"), njs_str("2011") }, + { njs_str("var d = new Date(2011, 5); d.getMonth()"), + njs_str("5") }, + + { njs_str("var d = new Date(2011, 6, 0, 0, 0, 0, -1); d.getMonth()"), + njs_str("5") }, + + { njs_str("var d = new Date(2011, 6, 31, 23, 59, 59, 999); d.getMonth()"), + njs_str("6") }, + + { njs_str("var d = new Date(2011, 6, 31, 23, 59, 59, 1000); d.getMonth()"), + njs_str("7") }, + { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getMonth()"), njs_str("5") }, From xeioex at nginx.com Fri Oct 11 12:34:50 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 11 Oct 2019 12:34:50 +0000 Subject: [njs] Fixed type of Date.prototype. Message-ID: details: https://hg.nginx.org/njs/rev/9944f6e9f33a branches: changeset: 1181:9944f6e9f33a user: Artem S. Povalyukhin date: Fri Oct 11 08:01:03 2019 +0300 description: Fixed type of Date.prototype. This closes #237 issue on Github. diffstat: src/njs_builtin.c | 3 +-- src/test/njs_unit_test.c | 12 +++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diffs (44 lines): diff -r eb57c1e27495 -r 9944f6e9f33a src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 10 20:54:03 2019 +0300 +++ b/src/njs_builtin.c Fri Oct 11 08:01:03 2019 +0300 @@ -190,8 +190,7 @@ const njs_object_prototype_t njs_protot { .object = { .type = NJS_REGEXP } }, - { .date = { .time = NAN, - .object = { .type = NJS_DATE } } }, + { .object = { .type = NJS_OBJECT } }, { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), .object = { .type = NJS_OBJECT } } }, diff -r eb57c1e27495 -r 9944f6e9f33a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 10 20:54:03 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 11 08:01:03 2019 +0300 @@ -12002,12 +12002,6 @@ static njs_unit_test_t njs_test[] = "Date.prototype.toJSON.call(o, 1)"), njs_str("OK") }, - { njs_str("var d = new Date; d.__proto__"), - njs_str("Invalid Date") }, - - { njs_str("var d = new Date(); d.__proto__"), - njs_str("Invalid Date") }, - { njs_str("var d = new Date(); d.__proto__ === Date.prototype"), njs_str("true") }, @@ -12049,11 +12043,11 @@ static njs_unit_test_t njs_test[] = { njs_str("Date.prototype.__proto__ === Object.prototype"), njs_str("true") }, - { njs_str("Date.prototype"), - njs_str("Invalid Date") }, + { njs_str("njs.dump(Date.prototype)"), + njs_str("{}") }, { njs_str("Date.prototype.valueOf()"), - njs_str("NaN") }, + njs_str("TypeError: cannot convert object to date") }, { njs_str("Date.constructor === Function"), njs_str("true") }, From xeioex at nginx.com Fri Oct 11 12:34:51 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 11 Oct 2019 12:34:51 +0000 Subject: [njs] Fixed Date.prototype.setTime(). Message-ID: details: https://hg.nginx.org/njs/rev/a4e44e7e6f38 branches: changeset: 1182:a4e44e7e6f38 user: Artem S. Povalyukhin date: Fri Oct 11 06:50:33 2019 +0300 description: Fixed Date.prototype.setTime(). This closes #236 issue on Github. diffstat: src/njs_date.c | 15 +++++---------- src/test/njs_unit_test.c | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diffs (50 lines): diff -r 9944f6e9f33a -r a4e44e7e6f38 src/njs_date.c --- a/src/njs_date.c Fri Oct 11 08:01:03 2019 +0300 +++ b/src/njs_date.c Fri Oct 11 06:50:33 2019 +0300 @@ -1520,16 +1520,11 @@ njs_date_prototype_set_time(njs_vm_t *vm { double time; - time = njs_date(&args[0])->time; - - if (njs_fast_path(!isnan(time))) { - - if (nargs > 1) { - time = njs_number(&args[1]); - - } else { - time = NAN; - } + if (nargs > 1) { + time = njs_timeclip(njs_number(&args[1])); + + } else { + time = NAN; } njs_date(&args[0])->time = time; diff -r 9944f6e9f33a -r a4e44e7e6f38 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Oct 11 08:01:03 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 11 06:50:33 2019 +0300 @@ -11878,6 +11878,21 @@ static njs_unit_test_t njs_test[] = { njs_str("var d = new Date(); d.setTime(1308895200000); d.getTime()"), njs_str("1308895200000") }, + { njs_str("var d = new Date(); d.setTime(); d.getTime()"), + njs_str("NaN") }, + + { njs_str("var d = new Date(); d.setTime(Infinity); d.getTime()"), + njs_str("NaN") }, + + { njs_str("var d = new Date(); d.setTime(8.64e15 +1); d.getTime()"), + njs_str("NaN") }, + + { njs_str("var d = new Date(NaN); d.setTime(0); d.getTime()"), + njs_str("0") }, + + { njs_str("var d = new Date(); d.setTime(8.64e15); d.getTime()"), + njs_str("8640000000000000") }, + { njs_str("var d = new Date(1308895201625); d.setMilliseconds(5003);" "d.getTime()"), njs_str("1308895206003") }, From xeioex at nginx.com Fri Oct 11 14:25:48 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 11 Oct 2019 14:25:48 +0000 Subject: [njs] Fixed variable declaration with "from" name. Message-ID: details: https://hg.nginx.org/njs/rev/b4cd260f7b69 branches: changeset: 1183:b4cd260f7b69 user: Dmitry Volyntsev date: Fri Oct 11 17:08:28 2019 +0300 description: Fixed variable declaration with "from" name. Previously, "from" was declared as a reserved word. diffstat: src/njs_lexer.h | 1 - src/njs_lexer_keyword.c | 1 - src/njs_parser.c | 2 +- src/njs_parser.h | 21 +++++++++++++++++++++ src/test/njs_unit_test.c | 3 +++ 5 files changed, 25 insertions(+), 3 deletions(-) diffs (78 lines): diff -r a4e44e7e6f38 -r b4cd260f7b69 src/njs_lexer.h --- a/src/njs_lexer.h Fri Oct 11 06:50:33 2019 +0300 +++ b/src/njs_lexer.h Fri Oct 11 17:08:28 2019 +0300 @@ -214,7 +214,6 @@ typedef enum { NJS_TOKEN_CLEAR_TIMEOUT, NJS_TOKEN_IMPORT, - NJS_TOKEN_FROM, NJS_TOKEN_EXPORT, NJS_TOKEN_RESERVED, diff -r a4e44e7e6f38 -r b4cd260f7b69 src/njs_lexer_keyword.c --- a/src/njs_lexer_keyword.c Fri Oct 11 06:50:33 2019 +0300 +++ b/src/njs_lexer_keyword.c Fri Oct 11 17:08:28 2019 +0300 @@ -96,7 +96,6 @@ static const njs_keyword_t njs_keywords /* Module. */ { njs_str("import"), NJS_TOKEN_IMPORT, 0 }, - { njs_str("from"), NJS_TOKEN_FROM, 0 }, { njs_str("export"), NJS_TOKEN_EXPORT, 0 }, /* Reserved words. */ diff -r a4e44e7e6f38 -r b4cd260f7b69 src/njs_parser.c --- a/src/njs_parser.c Fri Oct 11 06:50:33 2019 +0300 +++ b/src/njs_parser.c Fri Oct 11 17:08:28 2019 +0300 @@ -1825,7 +1825,7 @@ njs_parser_import_statement(njs_vm_t *vm return token; } - token = njs_parser_match(vm, parser, token, NJS_TOKEN_FROM); + token = njs_parser_match_name(vm, parser, token, "from"); if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } diff -r a4e44e7e6f38 -r b4cd260f7b69 src/njs_parser.h --- a/src/njs_parser.h Fri Oct 11 06:50:33 2019 +0300 +++ b/src/njs_parser.h Fri Oct 11 17:08:28 2019 +0300 @@ -233,6 +233,27 @@ njs_parser_match(njs_vm_t *vm, njs_parse } +njs_inline njs_token_t +njs_parser_match_name(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, + const char *name) +{ + size_t len; + njs_str_t *text; + + len = njs_strlen(name); + text = njs_parser_text(parser); + + if (njs_fast_path(token == NJS_TOKEN_NAME + && text->length == len + && memcmp(text->start, name, len) == 0)) + { + return njs_parser_token(vm, parser); + } + + return njs_parser_unexpected_token(vm, parser, token); +} + + njs_inline njs_variable_t * njs_parser_variable_add(njs_vm_t *vm, njs_parser_t *parser, njs_variable_type_t type) diff -r a4e44e7e6f38 -r b4cd260f7b69 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Oct 11 06:50:33 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 11 17:08:28 2019 +0300 @@ -69,6 +69,9 @@ static njs_unit_test_t njs_test[] = { njs_str("var \n a, \n b; b"), njs_str("undefined") }, + { njs_str("var from = 2; from + 2"), + njs_str("4") }, + { njs_str("var a / ="), njs_str("SyntaxError: Unexpected token \"/\" in 1") }, From alexander.borisov at nginx.com Fri Oct 11 16:42:39 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 11 Oct 2019 16:42:39 +0000 Subject: [njs] Added default number of arguments expected by builtin functions. Message-ID: details: https://hg.nginx.org/njs/rev/30c1bde3f194 branches: changeset: 1184:30c1bde3f194 user: Alexander Borisov date: Fri Oct 11 19:41:51 2019 +0300 description: Added default number of arguments expected by builtin functions. This closes #207 issue on GitHub. diffstat: src/njs_array.c | 52 ++++++++++++++-------------- src/njs_boolean.c | 4 +- src/njs_builtin.c | 2 +- src/njs_crypto.c | 16 ++++---- src/njs_date.c | 95 +++++++++++++++++++++++++++-------------------------- src/njs_error.c | 7 ++- src/njs_fs.c | 14 +++--- src/njs_function.c | 40 +++++++--------------- src/njs_json.c | 4 +- src/njs_math.c | 70 +++++++++++++++++++------------------- src/njs_number.c | 22 ++++++------ src/njs_object.c | 42 +++++++++++----------- src/njs_parser.c | 7 +++- src/njs_regexp.c | 6 +- src/njs_string.c | 66 ++++++++++++++++++------------------ src/njs_value.h | 5 +- src/njs_vmcode.c | 2 + 17 files changed, 226 insertions(+), 228 deletions(-) diffs (truncated from 1966 to 1000 lines): diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_array.c --- a/src/njs_array.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_array.c Fri Oct 11 19:41:51 2019 +0300 @@ -304,7 +304,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("isArray"), - .value = njs_native_function(njs_array_is_array, 0), + .value = njs_native_function(njs_array_is_array, 1, 0), .writable = 1, .configurable = 1, }, @@ -314,7 +314,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("of"), - .value = njs_native_function(njs_array_of, 0), + .value = njs_native_function(njs_array_of, 0, 0), .writable = 1, .configurable = 1, }, @@ -2736,7 +2736,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("slice"), - .value = njs_native_function(njs_array_prototype_slice, + .value = njs_native_function(njs_array_prototype_slice, 2, NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG), .writable = 1, .configurable = 1, @@ -2745,7 +2745,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("push"), - .value = njs_native_function(njs_array_prototype_push, 0), + .value = njs_native_function(njs_array_prototype_push, 1, 0), .writable = 1, .configurable = 1, }, @@ -2753,7 +2753,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("pop"), - .value = njs_native_function(njs_array_prototype_pop, 0), + .value = njs_native_function(njs_array_prototype_pop, 0, 0), .writable = 1, .configurable = 1, }, @@ -2761,7 +2761,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("unshift"), - .value = njs_native_function(njs_array_prototype_unshift, 0), + .value = njs_native_function(njs_array_prototype_unshift, 1, 0), .writable = 1, .configurable = 1, }, @@ -2769,7 +2769,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("shift"), - .value = njs_native_function(njs_array_prototype_shift, 0), + .value = njs_native_function(njs_array_prototype_shift, 0, 0), .writable = 1, .configurable = 1, }, @@ -2777,7 +2777,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("splice"), - .value = njs_native_function(njs_array_prototype_splice, + .value = njs_native_function(njs_array_prototype_splice, 2, NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG), .writable = 1, .configurable = 1, @@ -2786,7 +2786,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reverse"), - .value = njs_native_function(njs_array_prototype_reverse, + .value = njs_native_function(njs_array_prototype_reverse, 0, NJS_OBJECT_ARG), .writable = 1, .configurable = 1, @@ -2795,7 +2795,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_array_prototype_to_string, 0), + .value = njs_native_function(njs_array_prototype_to_string, 0, 0), .writable = 1, .configurable = 1, }, @@ -2803,7 +2803,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("join"), - .value = njs_native_function(njs_array_prototype_join, + .value = njs_native_function(njs_array_prototype_join, 1, NJS_OBJECT_ARG, NJS_STRING_ARG), .writable = 1, .configurable = 1, @@ -2812,7 +2812,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("concat"), - .value = njs_native_function(njs_array_prototype_concat, 0), + .value = njs_native_function(njs_array_prototype_concat, 1, 0), .writable = 1, .configurable = 1, }, @@ -2820,7 +2820,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("indexOf"), - .value = njs_native_function(njs_array_prototype_index_of, + .value = njs_native_function(njs_array_prototype_index_of, 1, NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), .writable = 1, .configurable = 1, @@ -2829,7 +2829,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("lastIndexOf"), - .value = njs_native_function(njs_array_prototype_last_index_of, + .value = njs_native_function(njs_array_prototype_last_index_of, 1, NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), .writable = 1, .configurable = 1, @@ -2839,7 +2839,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("includes"), - .value = njs_native_function(njs_array_prototype_includes, + .value = njs_native_function(njs_array_prototype_includes, 1, NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), .writable = 1, .configurable = 1, @@ -2848,7 +2848,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("forEach"), - .value = njs_native_function(njs_array_prototype_for_each, 0), + .value = njs_native_function(njs_array_prototype_for_each, 1, 0), .writable = 1, .configurable = 1, }, @@ -2856,7 +2856,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("some"), - .value = njs_native_function(njs_array_prototype_some, 0), + .value = njs_native_function(njs_array_prototype_some, 1, 0), .writable = 1, .configurable = 1, }, @@ -2864,7 +2864,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("every"), - .value = njs_native_function(njs_array_prototype_every, 0), + .value = njs_native_function(njs_array_prototype_every, 1, 0), .writable = 1, .configurable = 1, }, @@ -2873,7 +2873,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("fill"), - .value = njs_native_function(njs_array_prototype_fill, + .value = njs_native_function(njs_array_prototype_fill, 1, NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2883,7 +2883,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("filter"), - .value = njs_native_function(njs_array_prototype_filter, 0), + .value = njs_native_function(njs_array_prototype_filter, 1, 0), .writable = 1, .configurable = 1, }, @@ -2892,7 +2892,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("find"), - .value = njs_native_function(njs_array_prototype_find, 0), + .value = njs_native_function(njs_array_prototype_find, 1, 0), .writable = 1, .configurable = 1, }, @@ -2901,7 +2901,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("findIndex"), - .value = njs_native_function(njs_array_prototype_find_index, 0), + .value = njs_native_function(njs_array_prototype_find_index, 1, 0), .writable = 1, .configurable = 1, }, @@ -2909,7 +2909,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("map"), - .value = njs_native_function(njs_array_prototype_map, 0), + .value = njs_native_function(njs_array_prototype_map, 1, 0), .writable = 1, .configurable = 1, }, @@ -2917,7 +2917,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reduce"), - .value = njs_native_function(njs_array_prototype_reduce, 0), + .value = njs_native_function(njs_array_prototype_reduce, 1, 0), .writable = 1, .configurable = 1, }, @@ -2925,7 +2925,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reduceRight"), - .value = njs_native_function(njs_array_prototype_reduce_right, 0), + .value = njs_native_function(njs_array_prototype_reduce_right, 1, 0), .writable = 1, .configurable = 1, }, @@ -2933,7 +2933,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("sort"), - .value = njs_native_function(njs_array_prototype_sort, 0), + .value = njs_native_function(njs_array_prototype_sort, 1, 0), .writable = 1, .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_boolean.c --- a/src/njs_boolean.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_boolean.c Fri Oct 11 19:41:51 2019 +0300 @@ -145,7 +145,7 @@ static const njs_object_prop_t njs_bool { .type = NJS_PROPERTY, .name = njs_string("valueOf"), - .value = njs_native_function(njs_boolean_prototype_value_of, 0), + .value = njs_native_function(njs_boolean_prototype_value_of, 0, 0), .writable = 1, .configurable = 1, }, @@ -153,7 +153,7 @@ static const njs_object_prop_t njs_bool { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_boolean_prototype_to_string, 0), + .value = njs_native_function(njs_boolean_prototype_to_string, 0, 0), .writable = 1, .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_builtin.c --- a/src/njs_builtin.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_builtin.c Fri Oct 11 19:41:51 2019 +0300 @@ -1117,7 +1117,7 @@ static const njs_object_prop_t njs_njs_ { .type = NJS_PROPERTY, .name = njs_string("dump"), - .value = njs_native_function(njs_dump_value, + .value = njs_native_function(njs_dump_value, 0, NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG), .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_crypto.c --- a/src/njs_crypto.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_crypto.c Fri Oct 11 19:41:51 2019 +0300 @@ -323,7 +323,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_hash_prototype_to_string, 0), + .value = njs_native_function(njs_hash_prototype_to_string, 0, 0), .writable = 1, .configurable = 1, }, @@ -331,7 +331,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("update"), - .value = njs_native_function(njs_hash_prototype_update, + .value = njs_native_function(njs_hash_prototype_update, 0, NJS_OBJECT_ARG, NJS_SKIP_ARG), .writable = 1, .configurable = 1, @@ -340,7 +340,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("digest"), - .value = njs_native_function(njs_hash_prototype_digest, + .value = njs_native_function(njs_hash_prototype_digest, 0, NJS_OBJECT_ARG, NJS_SKIP_ARG), .writable = 1, .configurable = 1, @@ -585,7 +585,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_hmac_prototype_to_string, 0), + .value = njs_native_function(njs_hmac_prototype_to_string, 0, 0), .writable = 1, .configurable = 1, }, @@ -593,7 +593,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("update"), - .value = njs_native_function(njs_hmac_prototype_update, + .value = njs_native_function(njs_hmac_prototype_update, 0, NJS_OBJECT_ARG, NJS_SKIP_ARG), .writable = 1, .configurable = 1, @@ -602,7 +602,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("digest"), - .value = njs_native_function(njs_hmac_prototype_digest, + .value = njs_native_function(njs_hmac_prototype_digest, 0, NJS_OBJECT_ARG, NJS_SKIP_ARG), .writable = 1, .configurable = 1, @@ -650,7 +650,7 @@ static const njs_object_prop_t njs_cryp { .type = NJS_PROPERTY, .name = njs_string("createHash"), - .value = njs_native_function(njs_crypto_create_hash, + .value = njs_native_function(njs_crypto_create_hash, 0, NJS_SKIP_ARG), .writable = 1, .configurable = 1, @@ -659,7 +659,7 @@ static const njs_object_prop_t njs_cryp { .type = NJS_PROPERTY, .name = njs_string("createHmac"), - .value = njs_native_function(njs_crypto_create_hmac, + .value = njs_native_function(njs_crypto_create_hmac, 0, NJS_SKIP_ARG), .writable = 1, .configurable = 1, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_date.c --- a/src/njs_date.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_date.c Fri Oct 11 19:41:51 2019 +0300 @@ -1016,7 +1016,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("UTC"), - .value = njs_native_function(njs_date_utc, 0), + .value = njs_native_function(njs_date_utc, 7, 0), .writable = 1, .configurable = 1, }, @@ -1024,7 +1024,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("now"), - .value = njs_native_function(njs_date_now, 0), + .value = njs_native_function(njs_date_now, 0, 0), .writable = 1, .configurable = 1, }, @@ -1032,7 +1032,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("parse"), - .value = njs_native_function(njs_date_parse, + .value = njs_native_function(njs_date_parse, 1, NJS_SKIP_ARG, NJS_STRING_ARG), .writable = 1, .configurable = 1, @@ -2034,7 +2034,8 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("valueOf"), - .value = njs_native_function(njs_date_prototype_value_of, NJS_DATE_ARG), + .value = njs_native_function(njs_date_prototype_value_of, 0, + NJS_DATE_ARG), .writable = 1, .configurable = 1, }, @@ -2042,7 +2043,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_date_prototype_to_string, + .value = njs_native_function(njs_date_prototype_to_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2051,7 +2052,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toDateString"), - .value = njs_native_function(njs_date_prototype_to_date_string, + .value = njs_native_function(njs_date_prototype_to_date_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2060,7 +2061,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toTimeString"), - .value = njs_native_function(njs_date_prototype_to_time_string, + .value = njs_native_function(njs_date_prototype_to_time_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2069,7 +2070,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toLocaleString"), - .value = njs_native_function(njs_date_prototype_to_string, + .value = njs_native_function(njs_date_prototype_to_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2078,7 +2079,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("toLocaleDateString"), - .value = njs_native_function(njs_date_prototype_to_date_string, + .value = njs_native_function(njs_date_prototype_to_date_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2087,7 +2088,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("toLocaleTimeString"), - .value = njs_native_function(njs_date_prototype_to_time_string, + .value = njs_native_function(njs_date_prototype_to_time_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2096,7 +2097,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toUTCString"), - .value = njs_native_function(njs_date_prototype_to_utc_string, + .value = njs_native_function(njs_date_prototype_to_utc_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2105,7 +2106,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toISOString"), - .value = njs_native_function(njs_date_prototype_to_iso_string, + .value = njs_native_function(njs_date_prototype_to_iso_string, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2114,7 +2115,8 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getTime"), - .value = njs_native_function(njs_date_prototype_value_of, NJS_DATE_ARG), + .value = njs_native_function(njs_date_prototype_value_of, 0, + NJS_DATE_ARG), .writable = 1, .configurable = 1, }, @@ -2122,7 +2124,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getFullYear"), - .value = njs_native_function(njs_date_prototype_get_full_year, + .value = njs_native_function(njs_date_prototype_get_full_year, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2131,7 +2133,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCFullYear"), - .value = njs_native_function(njs_date_prototype_get_utc_full_year, + .value = njs_native_function(njs_date_prototype_get_utc_full_year, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2140,7 +2142,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getMonth"), - .value = njs_native_function(njs_date_prototype_get_month, + .value = njs_native_function(njs_date_prototype_get_month, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2149,7 +2151,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCMonth"), - .value = njs_native_function(njs_date_prototype_get_utc_month, + .value = njs_native_function(njs_date_prototype_get_utc_month, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2158,7 +2160,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getDate"), - .value = njs_native_function(njs_date_prototype_get_date, + .value = njs_native_function(njs_date_prototype_get_date, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2167,7 +2169,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCDate"), - .value = njs_native_function(njs_date_prototype_get_utc_date, + .value = njs_native_function(njs_date_prototype_get_utc_date, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2176,7 +2178,8 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getDay"), - .value = njs_native_function(njs_date_prototype_get_day, NJS_DATE_ARG), + .value = njs_native_function(njs_date_prototype_get_day, 0, + NJS_DATE_ARG), .writable = 1, .configurable = 1, }, @@ -2184,7 +2187,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCDay"), - .value = njs_native_function(njs_date_prototype_get_utc_day, + .value = njs_native_function(njs_date_prototype_get_utc_day, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2193,7 +2196,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getHours"), - .value = njs_native_function(njs_date_prototype_get_hours, + .value = njs_native_function(njs_date_prototype_get_hours, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2202,7 +2205,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCHours"), - .value = njs_native_function(njs_date_prototype_get_utc_hours, + .value = njs_native_function(njs_date_prototype_get_utc_hours, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2211,7 +2214,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getMinutes"), - .value = njs_native_function(njs_date_prototype_get_minutes, + .value = njs_native_function(njs_date_prototype_get_minutes, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2220,7 +2223,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCMinutes"), - .value = njs_native_function(njs_date_prototype_get_utc_minutes, + .value = njs_native_function(njs_date_prototype_get_utc_minutes, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2229,7 +2232,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getSeconds"), - .value = njs_native_function(njs_date_prototype_get_seconds, + .value = njs_native_function(njs_date_prototype_get_seconds, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2238,7 +2241,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("getUTCSeconds"), - .value = njs_native_function(njs_date_prototype_get_seconds, + .value = njs_native_function(njs_date_prototype_get_seconds, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2247,7 +2250,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("getMilliseconds"), - .value = njs_native_function(njs_date_prototype_get_milliseconds, + .value = njs_native_function(njs_date_prototype_get_milliseconds, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2256,7 +2259,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("getUTCMilliseconds"), - .value = njs_native_function(njs_date_prototype_get_milliseconds, + .value = njs_native_function(njs_date_prototype_get_milliseconds, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2265,7 +2268,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("getTimezoneOffset"), - .value = njs_native_function(njs_date_prototype_get_timezone_offset, + .value = njs_native_function(njs_date_prototype_get_timezone_offset, 0, NJS_DATE_ARG), .writable = 1, .configurable = 1, @@ -2274,7 +2277,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setTime"), - .value = njs_native_function(njs_date_prototype_set_time, + .value = njs_native_function(njs_date_prototype_set_time, 1, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2283,7 +2286,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("setMilliseconds"), - .value = njs_native_function(njs_date_prototype_set_milliseconds, + .value = njs_native_function(njs_date_prototype_set_milliseconds, 1, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2292,7 +2295,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_long_string("setUTCMilliseconds"), - .value = njs_native_function(njs_date_prototype_set_milliseconds, + .value = njs_native_function(njs_date_prototype_set_milliseconds, 1, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2301,7 +2304,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setSeconds"), - .value = njs_native_function(njs_date_prototype_set_seconds, + .value = njs_native_function(njs_date_prototype_set_seconds, 2, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2310,7 +2313,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCSeconds"), - .value = njs_native_function(njs_date_prototype_set_seconds, + .value = njs_native_function(njs_date_prototype_set_seconds, 2, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2319,7 +2322,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setMinutes"), - .value = njs_native_function(njs_date_prototype_set_minutes, + .value = njs_native_function(njs_date_prototype_set_minutes, 3, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2329,7 +2332,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCMinutes"), - .value = njs_native_function(njs_date_prototype_set_utc_minutes, + .value = njs_native_function(njs_date_prototype_set_utc_minutes, 3, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2339,7 +2342,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setHours"), - .value = njs_native_function(njs_date_prototype_set_hours, + .value = njs_native_function(njs_date_prototype_set_hours, 4, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2349,7 +2352,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCHours"), - .value = njs_native_function(njs_date_prototype_set_utc_hours, + .value = njs_native_function(njs_date_prototype_set_utc_hours, 4, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2359,7 +2362,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setDate"), - .value = njs_native_function(njs_date_prototype_set_date, + .value = njs_native_function(njs_date_prototype_set_date, 1, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2368,7 +2371,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCDate"), - .value = njs_native_function(njs_date_prototype_set_utc_date, + .value = njs_native_function(njs_date_prototype_set_utc_date, 1, NJS_DATE_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2377,7 +2380,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setMonth"), - .value = njs_native_function(njs_date_prototype_set_month, + .value = njs_native_function(njs_date_prototype_set_month, 2, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2386,7 +2389,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCMonth"), - .value = njs_native_function(njs_date_prototype_set_utc_month, + .value = njs_native_function(njs_date_prototype_set_utc_month, 2, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -2395,7 +2398,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setFullYear"), - .value = njs_native_function(njs_date_prototype_set_full_year, + .value = njs_native_function(njs_date_prototype_set_full_year, 3, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2405,7 +2408,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("setUTCFullYear"), - .value = njs_native_function(njs_date_prototype_set_utc_full_year, + .value = njs_native_function(njs_date_prototype_set_utc_full_year, 3, NJS_DATE_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG), .writable = 1, @@ -2415,7 +2418,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("toJSON"), - .value = njs_native_function(njs_date_prototype_to_json, 0), + .value = njs_native_function(njs_date_prototype_to_json, 1, 0), .writable = 1, .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_error.c --- a/src/njs_error.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_error.c Fri Oct 11 19:41:51 2019 +0300 @@ -734,7 +734,7 @@ static const njs_object_prop_t njs_erro { .type = NJS_PROPERTY, .name = njs_string("valueOf"), - .value = njs_native_function(njs_error_prototype_value_of, 0), + .value = njs_native_function(njs_error_prototype_value_of, 0, 0), .writable = 1, .configurable = 1, }, @@ -742,7 +742,7 @@ static const njs_object_prop_t njs_erro { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_error_prototype_to_string, 0), + .value = njs_native_function(njs_error_prototype_to_string, 0, 0), .writable = 1, .configurable = 1, }, @@ -816,7 +816,8 @@ static const njs_object_prop_t njs_inte { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_internal_error_prototype_to_string, 0), + .value = njs_native_function(njs_internal_error_prototype_to_string, + 0, 0), .writable = 1, .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_fs.c --- a/src/njs_fs.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_fs.c Fri Oct 11 19:41:51 2019 +0300 @@ -1140,7 +1140,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("readFile"), - .value = njs_native_function(njs_fs_read_file, 0), + .value = njs_native_function(njs_fs_read_file, 0, 0), .writable = 1, .configurable = 1, }, @@ -1148,7 +1148,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("readFileSync"), - .value = njs_native_function(njs_fs_read_file_sync, 0), + .value = njs_native_function(njs_fs_read_file_sync, 0, 0), .writable = 1, .configurable = 1, }, @@ -1156,7 +1156,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("appendFile"), - .value = njs_native_function(njs_fs_append_file, 0), + .value = njs_native_function(njs_fs_append_file, 0, 0), .writable = 1, .configurable = 1, }, @@ -1164,7 +1164,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("appendFileSync"), - .value = njs_native_function(njs_fs_append_file_sync, 0), + .value = njs_native_function(njs_fs_append_file_sync, 0, 0), .writable = 1, .configurable = 1, }, @@ -1172,7 +1172,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("writeFile"), - .value = njs_native_function(njs_fs_write_file, 0), + .value = njs_native_function(njs_fs_write_file, 0, 0), .writable = 1, .configurable = 1, }, @@ -1180,7 +1180,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("writeFileSync"), - .value = njs_native_function(njs_fs_write_file_sync, 0), + .value = njs_native_function(njs_fs_write_file_sync, 0, 0), .writable = 1, .configurable = 1, }, @@ -1188,7 +1188,7 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, .name = njs_string("renameSync"), - .value = njs_native_function(njs_fs_rename_sync, NJS_STRING_ARG, + .value = njs_native_function(njs_fs_rename_sync, 0, NJS_STRING_ARG, NJS_STRING_ARG, 0), .writable = 1, .configurable = 1, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_function.c --- a/src/njs_function.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_function.c Fri Oct 11 19:41:51 2019 +0300 @@ -1032,10 +1032,8 @@ static njs_int_t njs_function_instance_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - njs_uint_t n; - njs_object_t *proto; - njs_function_t *function; - njs_function_lambda_t *lambda; + njs_object_t *proto; + njs_function_t *function; proto = njs_object(value); @@ -1054,26 +1052,7 @@ njs_function_instance_length(njs_vm_t *v function = (njs_function_t *) proto; - if (function->native) { - for (n = function->args_offset; n < NJS_ARGS_TYPES_MAX; n++) { - if (function->args_types[n] == 0) { - break; - } - } - - } else { - lambda = function->u.lambda; - n = lambda->nargs + 1 - lambda->rest_parameters; - } - - if (n >= function->args_offset) { - n -= function->args_offset; - - } else { - n = 0; - } - - njs_set_number(retval, n); + njs_set_number(retval, function->args_count); return NJS_OK; } @@ -1224,6 +1203,13 @@ njs_function_prototype_bind(njs_vm_t *vm args++; } + if (nargs > function->args_count) { + function->args_count = 0; + + } else { + function->args_count -= nargs - 1; + } + function->args_offset = nargs; size = nargs * sizeof(njs_value_t); @@ -1273,7 +1259,7 @@ static const njs_object_prop_t njs_func { .type = NJS_PROPERTY, .name = njs_string("call"), - .value = njs_native_function(njs_function_prototype_call, 0), + .value = njs_native_function(njs_function_prototype_call, 1, 0), .writable = 1, .configurable = 1, }, @@ -1281,7 +1267,7 @@ static const njs_object_prop_t njs_func { .type = NJS_PROPERTY, .name = njs_string("apply"), - .value = njs_native_function(njs_function_prototype_apply, 0), + .value = njs_native_function(njs_function_prototype_apply, 2, 0), .writable = 1, .configurable = 1, }, @@ -1289,7 +1275,7 @@ static const njs_object_prop_t njs_func { .type = NJS_PROPERTY, .name = njs_string("bind"), - .value = njs_native_function(njs_function_prototype_bind, 0), + .value = njs_native_function(njs_function_prototype_bind, 1, 0), .writable = 1, .configurable = 1, }, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_json.c --- a/src/njs_json.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_json.c Fri Oct 11 19:41:51 2019 +0300 @@ -2101,7 +2101,7 @@ static const njs_object_prop_t njs_json { .type = NJS_PROPERTY, .name = njs_string("parse"), - .value = njs_native_function(njs_json_parse, + .value = njs_native_function(njs_json_parse, 2, NJS_SKIP_ARG, NJS_STRING_ARG, NJS_OBJECT_ARG), .writable = 1, @@ -2112,7 +2112,7 @@ static const njs_object_prop_t njs_json { .type = NJS_PROPERTY, .name = njs_string("stringify"), - .value = njs_native_function(njs_json_stringify, + .value = njs_native_function(njs_json_stringify, 3, NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_SKIP_ARG), .writable = 1, diff -r b4cd260f7b69 -r 30c1bde3f194 src/njs_math.c --- a/src/njs_math.c Fri Oct 11 17:08:28 2019 +0300 +++ b/src/njs_math.c Fri Oct 11 19:41:51 2019 +0300 @@ -833,7 +833,7 @@ static const njs_object_prop_t njs_math { .type = NJS_PROPERTY, .name = njs_string("abs"), - .value = njs_native_function(njs_object_math_abs, + .value = njs_native_function(njs_object_math_abs, 1, NJS_SKIP_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -842,7 +842,7 @@ static const njs_object_prop_t njs_math { .type = NJS_PROPERTY, .name = njs_string("acos"), - .value = njs_native_function(njs_object_math_acos, + .value = njs_native_function(njs_object_math_acos, 1, NJS_SKIP_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -852,7 +852,7 @@ static const njs_object_prop_t njs_math { .type = NJS_PROPERTY, .name = njs_string("acosh"), - .value = njs_native_function(njs_object_math_acosh, + .value = njs_native_function(njs_object_math_acosh, 1, NJS_SKIP_ARG, NJS_NUMBER_ARG), .writable = 1, .configurable = 1, @@ -861,7 +861,7 @@ static const njs_object_prop_t njs_math { From Alan.Andrea at refinitiv.com Sun Oct 13 23:06:42 2019 From: Alan.Andrea at refinitiv.com (Alan.Andrea at refinitiv.com) Date: Sun, 13 Oct 2019 23:06:42 +0000 Subject: Help with nginx running on AWS Fargate and hitting an S3 Website bucket In-Reply-To: <2F29F5F9B9DF2244AF230239EB600AD437F0CA02@C111HBREMBX71.ERF.thomson.com> References: <2F29F5F9B9DF2244AF230239EB600AD437F0C9BB@C111HBREMBX71.ERF.thomson.com> <2F29F5F9B9DF2244AF230239EB600AD437F0C9E9@C111HBREMBX71.ERF.thomson.com> <2F29F5F9B9DF2244AF230239EB600AD437F0CA02@C111HBREMBX71.ERF.thomson.com> Message-ID: <2F29F5F9B9DF2244AF230239EB600AD437F0CA2F@C111HBREMBX71.ERF.thomson.com> Hi: I am having a lot of issues attempting to run NGINX on Fargate whereby I am getting a 502 bad gateway error when hitting My listener that should be doing a proxy-pass to an S3 website bucket that I created. I am not sure if this is due to NGINX being unable to do the nameserver resolving even though I have specified a resolver at both the server level and at the listener level. Neither of which work. ( using googles public nameserver: 8.8.8.8) Also, I used the standard docker image for NGINX obtained from the NGINX website. The S3 website bucket is public also just to mention and is serving up the site without issues. This is the error that I get: << Actual hostnames removed for privacy concerns>> 2019/10/12 17:30:45 [error] 7#7: 3 somebucket.s3-website-eu-west-1.amazonaws.com could not be resolved (110: Operation timed out), client: 198.179.137.213, server: somehost at somewhere.com, request: "GET /login/ HTTP/1.1", host: somehost at somewhere.com If anyone has a successful example of running NGINX on Fargate and hitting and S3 website, please let me know. Thanks, Alan Here is my nginx.conf file: user nginx; worker_processes 1; error_log /dev/stdout debug; pid /var/run/nginx.pid; events { worker_connections 1024; } http { server_names_hash_bucket_size 256; server_names_hash_max_size 512; include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /dev/stdout main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; index index.html; server { listen 80; server_name *.someserver at somewhere.com; access_log /dev/stdout; error_log /dev/stdout; location /login/ { resolver 8.8.8.8; set $bucket "somebucket.s3-website-eu-west-1.amazonaws.com"; rewrite ^([^.]*[^/])$ $1/ permanent; proxy_pass http://$bucket; proxy_redirect off; proxy_set_header Host $bucket; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_hide_header x-amz-id-2; proxy_hide_header x-amz-request-id; } } } ________________________________ This e-mail is for the sole use of the intended recipient and contains information that may be privileged and/or confidential. If you are not an intended recipient, please notify the sender by return e-mail and delete this e-mail and any attachments. Certain required legal entity disclosures can be accessed on our website. -------------- next part -------------- An HTML attachment was scrubbed... URL: From sangdeuk.kwon at quantil.com Tue Oct 15 06:11:12 2019 From: sangdeuk.kwon at quantil.com (Sangdeuk Kwon) Date: Tue, 15 Oct 2019 15:11:12 +0900 Subject: [PATCH] nginx cannot respond when big response header with proxy_buffering is off and limit_rate is set. Message-ID: # HG changeset patch # User Sangdeuk Kwon # Date 1571119628 -32400 # Tue Oct 15 15:07:08 2019 +0900 # Node ID a484d65af8cefef5d6501872a6b72a0623fd9af4 # Parent 6208c5418c88ce8ecc656b40704a752cb7c7648a nginx cannot respond when big response header with proxy_buffering is off and limit_rate is set. If proxy_buffering is off and limit_rate is 1M, nginx cannot respond when response header is over 1k. currently, nginx disable limit_rate before sending body. It should be disabled before sending header. http { server { listen 8100; server_name localhost; limit_rate 1M; location / { proxy_buffering off; proxy_pass http://127.0.0.1:8000; } } server { listen 8000; server_name localhost; location / { return 200 "test\n"; add_header Server_flag_C_policy_R-Location_flag_S_policy_000 "000"; add_header Server_flag_C_policy_R-Location_flag_S_policy_001 "001"; add_header Server_flag_C_policy_R-Location_flag_S_policy_002 "002"; add_header Server_flag_C_policy_R-Location_flag_S_policy_003 "003"; add_header Server_flag_C_policy_R-Location_flag_S_policy_004 "004"; add_header Server_flag_C_policy_R-Location_flag_S_policy_005 "005"; add_header Server_flag_C_policy_R-Location_flag_S_policy_006 "006"; add_header Server_flag_C_policy_R-Location_flag_S_policy_007 "007"; add_header Server_flag_C_policy_R-Location_flag_S_policy_008 "008"; add_header Server_flag_C_policy_R-Location_flag_S_policy_009 "009"; add_header Server_flag_C_policy_R-Location_flag_S_policy_010 "010"; add_header Server_flag_C_policy_R-Location_flag_S_policy_011 "011"; add_header Server_flag_C_policy_R-Location_flag_S_policy_012 "012"; add_header Server_flag_C_policy_R-Location_flag_S_policy_013 "013"; add_header Server_flag_C_policy_R-Location_flag_S_policy_014 "014"; add_header Server_flag_C_policy_R-Location_flag_S_policy_015 "015"; add_header Server_flag_C_policy_R-Location_flag_S_policy_016 "016"; add_header Server_flag_C_policy_R-Location_flag_S_policy_017 "017"; add_header Server_flag_C_policy_R-Location_flag_S_policy_018 "018"; add_header Server_flag_C_policy_R-Location_flag_S_policy_019 "019"; add_header Server_flag_C_policy_R-Location_flag_S_policy_020 "020"; add_header Server_flag_C_policy_R-Location_flag_S_policy_021 "021"; add_header Server_flag_C_policy_R-Location_flag_S_policy_022 "022"; add_header Server_flag_C_policy_R-Location_flag_S_policy_023 "023"; add_header Server_flag_C_policy_R-Location_flag_S_policy_024 "024"; add_header Server_flag_C_policy_R-Location_flag_S_policy_025 "025"; add_header Server_flag_C_policy_R-Location_flag_S_policy_026 "026"; add_header Server_flag_C_policy_R-Location_flag_S_policy_027 "027"; add_header Server_flag_C_policy_R-Location_flag_S_policy_028 "028"; add_header Server_flag_C_policy_R-Location_flag_S_policy_029 "029"; } } } diff -r 6208c5418c88 -r a484d65af8ce src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Tue Oct 08 21:56:14 2019 +0300 +++ b/src/http/ngx_http_upstream.c Tue Oct 15 15:07:08 2019 +0900 @@ -2905,6 +2905,11 @@ ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; + if (!u->buffering) { + r->limit_rate = 0; + r->limit_rate_set = 1; + } + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) { @@ -2975,9 +2980,6 @@ r->write_event_handler = ngx_http_upstream_process_non_buffered_downstream; - r->limit_rate = 0; - r->limit_rate_set = 1; - if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; -------------- next part -------------- An HTML attachment was scrubbed... URL: From ru at nginx.com Tue Oct 15 11:46:44 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 15 Oct 2019 11:46:44 +0000 Subject: [nginx] Fixed header parsing with ignore_invalid_headers switched off. Message-ID: details: https://hg.nginx.org/nginx/rev/8f55cb5c7e79 branches: changeset: 7580:8f55cb5c7e79 user: Ruslan Ermilov date: Tue Oct 15 14:46:10 2019 +0300 description: Fixed header parsing with ignore_invalid_headers switched off. The parsing was broken when the first character of the header name was invalid. Based on a patch by Alan Kemp. diffstat: src/http/ngx_http_parse.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (21 lines): diff -r 6208c5418c88 -r 8f55cb5c7e79 src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c Tue Oct 08 21:56:14 2019 +0300 +++ b/src/http/ngx_http_parse.c Tue Oct 15 14:46:10 2019 +0300 @@ -912,6 +912,8 @@ ngx_http_parse_header_line(ngx_http_requ i = 1; } else { + hash = 0; + i = 0; r->invalid_header = 1; } @@ -922,6 +924,8 @@ ngx_http_parse_header_line(ngx_http_requ return NGX_HTTP_PARSE_INVALID_HEADER; } + hash = 0; + i = 0; r->invalid_header = 1; break; From xeioex at nginx.com Tue Oct 15 17:10:04 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 15 Oct 2019 17:10:04 +0000 Subject: [njs] HTTP: improved getting of special headers from r.headersIn. Message-ID: details: https://hg.nginx.org/njs/rev/eae54eb41bfc branches: changeset: 1185:eae54eb41bfc user: Dmitry Volyntsev date: Tue Oct 15 20:09:49 2019 +0300 description: HTTP: improved getting of special headers from r.headersIn. If multiple "Cookie" or "X-Forwarded-For" are present they are combined into a single return value. This closes #201 issue on Github. diffstat: nginx/ngx_http_js_module.c | 73 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 72 insertions(+), 1 deletions(-) diffs (96 lines): diff -r 30c1bde3f194 -r eae54eb41bfc nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Fri Oct 11 19:41:51 2019 +0300 +++ b/nginx/ngx_http_js_module.c Tue Oct 15 20:09:49 2019 +0300 @@ -1514,13 +1514,37 @@ static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data) { + u_char *p, *end, sep; + size_t len; njs_str_t *v; - ngx_table_elt_t *h; + ngx_uint_t i, n; + ngx_array_t *a; + ngx_table_elt_t *h, **hh; ngx_http_request_t *r; r = (ngx_http_request_t *) obj; v = (njs_str_t *) data; + if (v->length == njs_length("Cookie") + && ngx_strncasecmp(v->start, (u_char *) "Cookie", + v->length) == 0) + { + sep = ';'; + a = &r->headers_in.cookies; + goto multi; + } + +#if (NGX_HTTP_X_FORWARDED_FOR) + if (v->length == njs_length("X-Forwarded-For") + && ngx_strncasecmp(v->start, (u_char *) "X-Forwarded-For", + v->length) == 0) + { + sep = ','; + a = &r->headers_in.x_forwarded_for; + goto multi; + } +#endif + h = ngx_http_js_get_header(&r->headers_in.headers.part, v->start, v->length); if (h == NULL) { @@ -1529,6 +1553,53 @@ ngx_http_js_ext_get_header_in(njs_vm_t * } return njs_vm_value_string_set(vm, value, h->value.data, h->value.len); + +multi: + + /* Cookie, X-Forwarded-For */ + + n = a->nelts; + hh = a->elts; + + len = 0; + + for (i = 0; i < n; i++) { + len += hh[i]->value.len + 2; + } + + if (len == 0) { + njs_value_undefined_set(value); + return NJS_OK; + } + + len -= 2; + + if (n == 1) { + return njs_vm_value_string_set(vm, value, (*hh)->value.data, + (*hh)->value.len); + } + + p = njs_vm_value_string_alloc(vm, value, len); + if (p == NULL) { + return NJS_ERROR; + } + + end = p + len; + + + for (i = 0; /* void */ ; i++) { + + p = ngx_copy(p, hh[i]->value.data, hh[i]->value.len); + + if (p == end) { + break; + } + + *p++ = sep; + *p++ = ' '; + } + + return NJS_OK; } From mdounin at mdounin.ru Thu Oct 17 13:07:59 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 17 Oct 2019 13:07:59 +0000 Subject: [nginx] Event pipe: disabled c->read->available checking for SSL. Message-ID: details: https://hg.nginx.org/nginx/rev/afceb32f3a8a branches: changeset: 7581:afceb32f3a8a user: Maxim Dounin date: Thu Oct 17 16:02:03 2019 +0300 description: Event pipe: disabled c->read->available checking for SSL. In SSL connections, data can be buffered by the SSL layer, and it is wrong to avoid doing c->recv_chain() if c->read->available is 0 and c->read->pending_eof is set. And tests show that the optimization in question indeed can result in incorrect detection of premature connection close if upstream closes the connection without sending a close notify alert at the same time. Fix is to disable c->read->available optimization for SSL connections. diffstat: src/event/ngx_event_pipe.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diffs (16 lines): diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -172,7 +172,11 @@ ngx_event_pipe_read_upstream(ngx_event_p */ if (p->upstream->read->available == 0 - && p->upstream->read->pending_eof) + && p->upstream->read->pending_eof +#if (NGX_SSL) + && !p->upstream->ssl +#endif + ) { p->upstream->read->ready = 0; p->upstream->read->eof = 1; From mdounin at mdounin.ru Thu Oct 17 13:08:00 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 17 Oct 2019 13:08:00 +0000 Subject: [nginx] SSL: improved ngx_ssl_recv_chain() to stop if c->read->ready is 0. Message-ID: details: https://hg.nginx.org/nginx/rev/70749256af79 branches: changeset: 7582:70749256af79 user: Maxim Dounin date: Thu Oct 17 16:02:13 2019 +0300 description: SSL: improved ngx_ssl_recv_chain() to stop if c->read->ready is 0. As long as there are data to read in the socket, yet the amount of data is less than total size of the buffers in the chain, this saves one unneeded read() syscall. Before this change, reading only stopped if ngx_ssl_recv() returned no data, that is, two read() syscalls in a row returned EAGAIN. diffstat: src/event/ngx_event_openssl.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1922,6 +1922,10 @@ ngx_ssl_recv_chain(ngx_connection_t *c, last += n; bytes += n; + if (!c->read->ready) { + return bytes; + } + if (last == b->end) { cl = cl->next; From mdounin at mdounin.ru Thu Oct 17 13:08:02 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 17 Oct 2019 13:08:02 +0000 Subject: [nginx] Events: available bytes calculation via ioctl(FIONREAD). Message-ID: details: https://hg.nginx.org/nginx/rev/efd71d49bde0 branches: changeset: 7583:efd71d49bde0 user: Maxim Dounin date: Thu Oct 17 16:02:19 2019 +0300 description: Events: available bytes calculation via ioctl(FIONREAD). This makes it possible to avoid looping for a long time while working with a fast enough peer when data are added to the socket buffer faster than we are able to read and process them (ticket #1431). This is basically what we already do on FreeBSD with kqueue, where information about the number of bytes in the socket buffer is returned by the kevent() call. With other event methods rev->available is now set to -1 when the socket is ready for reading. Later in ngx_recv() and ngx_recv_chain(), if full buffer is received, real number of bytes in the socket buffer is retrieved using ioctl(FIONREAD). Reading more than this number of bytes ensures that even with edge-triggered event methods the event will be triggered again, so it is safe to stop processing of the socket and switch to other connections. Using ioctl(FIONREAD) only after reading a full buffer is an optimization. With this approach we only call ioctl(FIONREAD) when there are at least two recv()/readv() calls. diffstat: auto/unix | 12 ++++++++ src/event/modules/ngx_devpoll_module.c | 1 + src/event/modules/ngx_epoll_module.c | 3 +- src/event/modules/ngx_eventport_module.c | 1 + src/event/modules/ngx_poll_module.c | 1 + src/event/modules/ngx_select_module.c | 1 + src/event/modules/ngx_win32_poll_module.c | 1 + src/event/modules/ngx_win32_select_module.c | 1 + src/event/ngx_event.h | 9 +----- src/os/unix/ngx_readv_chain.c | 36 ++++++++++++++++++++++++++- src/os/unix/ngx_recv.c | 36 ++++++++++++++++++++++++++- src/os/unix/ngx_socket.h | 7 +++++ src/os/win32/ngx_socket.c | 15 +++++++++++ src/os/win32/ngx_socket.h | 3 ++ src/os/win32/ngx_win32_config.h | 4 ++ src/os/win32/ngx_wsarecv.c | 39 +++++++++++++++++++++++++++++ src/os/win32/ngx_wsarecv_chain.c | 35 ++++++++++++++++++++++++++ 17 files changed, 193 insertions(+), 12 deletions(-) diffs (399 lines): diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -943,6 +943,18 @@ ngx_feature_test="int i = FIONBIO; print . auto/feature +ngx_feature="ioctl(FIONREAD)" +ngx_feature_name="NGX_HAVE_FIONREAD" +ngx_feature_run=no +ngx_feature_incs="#include + #include + $NGX_INCLUDE_SYS_FILIO_H" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int i = FIONREAD; printf(\"%d\", i)" +. auto/feature + + ngx_feature="struct tm.tm_gmtoff" ngx_feature_name="NGX_HAVE_GMTOFF" ngx_feature_run=no diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -495,6 +495,7 @@ ngx_devpoll_process_events(ngx_cycle_t * if ((revents & POLLIN) && rev->active) { rev->ready = 1; + rev->available = -1; if (flags & NGX_POST_EVENTS) { queue = rev->accept ? &ngx_posted_accept_events diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -886,11 +886,10 @@ ngx_epoll_process_events(ngx_cycle_t *cy if (revents & EPOLLRDHUP) { rev->pending_eof = 1; } - - rev->available = 1; #endif rev->ready = 1; + rev->available = -1; if (flags & NGX_POST_EVENTS) { queue = rev->accept ? &ngx_posted_accept_events diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -559,6 +559,7 @@ ngx_eventport_process_events(ngx_cycle_t if (revents & POLLIN) { rev->ready = 1; + rev->available = -1; if (flags & NGX_POST_EVENTS) { queue = rev->accept ? &ngx_posted_accept_events diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -370,6 +370,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc ev = c->read; ev->ready = 1; + ev->available = -1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -330,6 +330,7 @@ ngx_select_process_events(ngx_cycle_t *c if (found) { ev->ready = 1; + ev->available = -1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; diff --git a/src/event/modules/ngx_win32_poll_module.c b/src/event/modules/ngx_win32_poll_module.c --- a/src/event/modules/ngx_win32_poll_module.c +++ b/src/event/modules/ngx_win32_poll_module.c @@ -380,6 +380,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc ev = c->read; ev->ready = 1; + ev->available = -1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -330,6 +330,7 @@ ngx_select_process_events(ngx_cycle_t *c if (found) { ev->ready = 1; + ev->available = -1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -91,21 +91,14 @@ struct ngx_event_s { * write: available space in buffer when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * - * epoll with EPOLLRDHUP: - * accept: 1 if accept many, 0 otherwise - * read: 1 if there can be data to read, 0 otherwise - * * iocp: TODO * * otherwise: * accept: 1 if accept many, 0 otherwise + * read: bytes to read when event is ready, -1 if not known */ -#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP) int available; -#else - unsigned available:1; -#endif ngx_event_handler_pt handler; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -60,7 +60,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx "readv: eof:%d, avail:%d", rev->pending_eof, rev->available); - if (!rev->available && !rev->pending_eof) { + if (rev->available == 0 && !rev->pending_eof) { return NGX_AGAIN; } } @@ -165,6 +165,40 @@ ngx_readv_chain(ngx_connection_t *c, ngx #endif +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0) { + rev->available -= n; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and readv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: avail:%d", rev->available); + + } else if (n == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + n = ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: avail:%d", rev->available); + } + +#endif + #if (NGX_HAVE_EPOLLRDHUP) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -57,7 +57,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha "recv: eof:%d, avail:%d", rev->pending_eof, rev->available); - if (!rev->available && !rev->pending_eof) { + if (rev->available == 0 && !rev->pending_eof) { rev->ready = 0; return NGX_AGAIN; } @@ -116,6 +116,40 @@ ngx_unix_recv(ngx_connection_t *c, u_cha #endif +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0) { + rev->available -= n; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and recv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: avail:%d", rev->available); + + } else if ((size_t) n == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + n = ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: avail:%d", rev->available); + } + +#endif + #if (NGX_HAVE_EPOLLRDHUP) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h --- a/src/os/unix/ngx_socket.h +++ b/src/os/unix/ngx_socket.h @@ -38,6 +38,13 @@ int ngx_blocking(ngx_socket_t s); #endif +#if (NGX_HAVE_FIONREAD) + +#define ngx_socket_nread(s, n) ioctl(s, FIONREAD, n) +#define ngx_socket_nread_n "ioctl(FIONREAD)" + +#endif + int ngx_tcp_nopush(ngx_socket_t s); int ngx_tcp_push(ngx_socket_t s); diff --git a/src/os/win32/ngx_socket.c b/src/os/win32/ngx_socket.c --- a/src/os/win32/ngx_socket.c +++ b/src/os/win32/ngx_socket.c @@ -28,6 +28,21 @@ ngx_blocking(ngx_socket_t s) int +ngx_socket_nread(ngx_socket_t s, int *n) +{ + unsigned long nread; + + if (ioctlsocket(s, FIONREAD, &nread) == -1) { + return -1; + } + + *n = nread; + + return 0; +} + + +int ngx_tcp_push(ngx_socket_t s) { return 0; diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h --- a/src/os/win32/ngx_socket.h +++ b/src/os/win32/ngx_socket.h @@ -31,6 +31,9 @@ int ngx_blocking(ngx_socket_t s); #define ngx_nonblocking_n "ioctlsocket(FIONBIO)" #define ngx_blocking_n "ioctlsocket(!FIONBIO)" +int ngx_socket_nread(ngx_socket_t s, int *n); +#define ngx_socket_nread_n "ioctlsocket(FIONREAD)" + #define ngx_shutdown_socket shutdown #define ngx_shutdown_socket_n "shutdown()" diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -273,6 +273,10 @@ typedef int sig_atomic_t #define NGX_HAVE_SO_SNDLOWAT 0 #endif +#ifndef NGX_HAVE_FIONREAD +#define NGX_HAVE_FIONREAD 1 +#endif + #define NGX_HAVE_GETADDRINFO 1 #define ngx_random rand diff --git a/src/os/win32/ngx_wsarecv.c b/src/os/win32/ngx_wsarecv.c --- a/src/os/win32/ngx_wsarecv.c +++ b/src/os/win32/ngx_wsarecv.c @@ -51,6 +51,45 @@ ngx_wsarecv(ngx_connection_t *c, u_char return n; } +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0 && bytes > 0) { + rev->available -= bytes; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and WSARecv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + + } else if (bytes == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + n = ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + } + +#endif + if (bytes < size) { rev->ready = 0; } diff --git a/src/os/win32/ngx_wsarecv_chain.c b/src/os/win32/ngx_wsarecv_chain.c --- a/src/os/win32/ngx_wsarecv_chain.c +++ b/src/os/win32/ngx_wsarecv_chain.c @@ -94,6 +94,41 @@ ngx_wsarecv_chain(ngx_connection_t *c, n return NGX_ERROR; } +#if (NGX_HAVE_FIONREAD) + + if (rev->available >= 0 && bytes > 0) { + rev->available -= bytes; + + /* + * negative rev->available means some additional bytes + * were received between kernel notification and WSARecv(), + * and therefore ev->ready can be safely reset even for + * edge-triggered event methods + */ + + if (rev->available < 0) { + rev->available = 0; + rev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + + } else if (bytes == size) { + + if (ngx_socket_nread(c->fd, &rev->available) == -1) { + rev->error = 1; + ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: avail:%d", rev->available); + } + +#endif + if (bytes < size) { rev->ready = 0; } From mdounin at mdounin.ru Thu Oct 17 13:08:04 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 17 Oct 2019 13:08:04 +0000 Subject: [nginx] SSL: available bytes handling (ticket #1431). Message-ID: details: https://hg.nginx.org/nginx/rev/9d2ad2fb4423 branches: changeset: 7584:9d2ad2fb4423 user: Maxim Dounin date: Thu Oct 17 16:02:24 2019 +0300 description: SSL: available bytes handling (ticket #1431). Added code to track number of bytes available in the socket. This makes it possible to avoid looping for a long time while working with fast enough peer when data are added to the socket buffer faster than we are able to read and process data. When kernel does not provide number of bytes available, it is retrieved using ioctl(FIONREAD) as long as a buffer is filled by SSL_read(). It is assumed that number of bytes returned by SSL_read() is close to the number of bytes read from the socket, as we do not use SSL compression. But even if it is not true for some reason, this is not important, as we post an additional reading event anyway. Note that data can be buffered at SSL layer, and it is not possible to simply stop reading at some point and wait till the event will be reported by the kernel again. This can be only done when there are no data in SSL buffers, and there is no good way to find out if it's the case. Instead of trying to figure out if SSL buffers are empty, this patch introduces events posted for the next event loop iteration - such events will be processed only on the next event loop iteration, after going into the kernel and retrieving additional events. This seems to be simple and reliable approach. diffstat: src/event/ngx_event.c | 7 ++++ src/event/ngx_event_openssl.c | 68 +++++++++++++++++++++++++++++++++++++++++++ src/event/ngx_event_openssl.h | 1 + src/event/ngx_event_posted.c | 1 + src/event/ngx_event_posted.h | 1 + 5 files changed, 78 insertions(+), 0 deletions(-) diffs (149 lines): diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -237,6 +237,12 @@ ngx_process_events_and_timers(ngx_cycle_ } } + if (!ngx_queue_empty(&ngx_posted_next_events)) { + ngx_queue_add(&ngx_posted_events, &ngx_posted_next_events); + ngx_queue_init(&ngx_posted_next_events); + timer = 0; + } + delta = ngx_current_msec; (void) ngx_process_events(cycle, timer, flags); @@ -639,6 +645,7 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif ngx_queue_init(&ngx_posted_accept_events); + ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -43,6 +43,7 @@ static ssize_t ngx_ssl_recv_early(ngx_co #endif static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); +static void ngx_ssl_next_read_handler(ngx_event_t *rev); #ifdef SSL_READ_EARLY_DATA_SUCCESS static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size); @@ -2003,6 +2004,48 @@ ngx_ssl_recv(ngx_connection_t *c, u_char if (size == 0) { c->read->ready = 1; + + if (c->read->available >= 0) { + c->read->available -= bytes; + + /* + * there can be data buffered at SSL layer, + * so we post an event to continue reading on the next + * iteration of the event loop + */ + + if (c->read->available < 0) { + c->read->available = 0; + c->read->ready = 0; + + if (c->ssl->next_read_handler == NULL) { + c->ssl->next_read_handler = c->read->handler; + c->read->handler = ngx_ssl_next_read_handler; + } + + ngx_post_event(c->read, &ngx_posted_next_events); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_read: avail:%d", c->read->available); + + } else { + +#if (NGX_HAVE_FIONREAD) + + if (ngx_socket_nread(c->fd, &c->read->available) == -1) { + c->read->error = 1; + ngx_connection_error(c, ngx_socket_errno, + ngx_socket_nread_n " failed"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_read: avail:%d", c->read->available); + +#endif + } + return bytes; } @@ -2285,6 +2328,31 @@ ngx_ssl_write_handler(ngx_event_t *wev) } +static void +ngx_ssl_next_read_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + + c = rev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL next read handler"); + + rev->handler = c->ssl->next_read_handler; + c->ssl->next_read_handler = NULL; + + if (!rev->ready) { + rev->ready = 1; + rev->available = -1; + } + + if (rev->posted) { + ngx_delete_posted_event(rev); + } + + rev->handler(rev); +} + + /* * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer * before the SSL_write() call to decrease a SSL overhead. diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -86,6 +86,7 @@ struct ngx_ssl_connection_s { ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_write_handler; + ngx_event_handler_pt next_read_handler; u_char early_buf; diff --git a/src/event/ngx_event_posted.c b/src/event/ngx_event_posted.c --- a/src/event/ngx_event_posted.c +++ b/src/event/ngx_event_posted.c @@ -11,6 +11,7 @@ ngx_queue_t ngx_posted_accept_events; +ngx_queue_t ngx_posted_next_events; ngx_queue_t ngx_posted_events; diff --git a/src/event/ngx_event_posted.h b/src/event/ngx_event_posted.h --- a/src/event/ngx_event_posted.h +++ b/src/event/ngx_event_posted.h @@ -42,6 +42,7 @@ void ngx_event_process_posted(ngx_cycle_ extern ngx_queue_t ngx_posted_accept_events; +extern ngx_queue_t ngx_posted_next_events; extern ngx_queue_t ngx_posted_events; From xeioex at nginx.com Fri Oct 18 13:27:45 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 18 Oct 2019 13:27:45 +0000 Subject: [njs] Fixed "caller" and "arguments" properties of a function instance. Message-ID: details: https://hg.nginx.org/njs/rev/ed4472f545a1 branches: changeset: 1186:ed4472f545a1 user: Artem S. Povalyukhin date: Sat Aug 24 05:41:46 2019 +0300 description: Fixed "caller" and "arguments" properties of a function instance. This closes #209 issue on Github. diffstat: src/njs_function.c | 40 +++++++++++++++++++++++++++++----------- src/test/njs_unit_test.c | 45 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 17 deletions(-) diffs (149 lines): diff -r eae54eb41bfc -r ed4472f545a1 src/njs_function.c --- a/src/njs_function.c Tue Oct 15 20:09:49 2019 +0300 +++ b/src/njs_function.c Sat Aug 24 05:41:46 2019 +0300 @@ -254,10 +254,11 @@ njs_function_rest_parameters_init(njs_vm static njs_int_t -njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_function_prototype_thrower(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) { - njs_type_error(vm, "\"caller\", \"callee\" properties may not be accessed"); + njs_type_error(vm, "\"caller\", \"callee\", \"arguments\" " + "properties may not be accessed"); return NJS_ERROR; } @@ -265,15 +266,12 @@ njs_function_arguments_thrower(njs_vm_t const njs_object_prop_t njs_arguments_object_instance_properties[] = { { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("caller"), - .value = njs_prop_handler(njs_function_arguments_thrower), - }, - - { - .type = NJS_PROPERTY_HANDLER, + .type = NJS_PROPERTY, .name = njs_string("callee"), - .value = njs_prop_handler(njs_function_arguments_thrower), + .value = njs_value(NJS_INVALID, 1, NAN), + .getter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .setter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .writable = NJS_ATTRIBUTE_UNSET, }, }; @@ -1279,6 +1277,26 @@ static const njs_object_prop_t njs_func .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("caller"), + .value = njs_value(NJS_INVALID, 1, NAN), + .getter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .setter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .writable = NJS_ATTRIBUTE_UNSET, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("arguments"), + .value = njs_value(NJS_INVALID, 1, NAN), + .getter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .setter = njs_native_function(njs_function_prototype_thrower, 0, 0), + .writable = NJS_ATTRIBUTE_UNSET, + .configurable = 1, + }, }; diff -r eae54eb41bfc -r ed4472f545a1 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Oct 15 20:09:49 2019 +0300 +++ b/src/test/njs_unit_test.c Sat Aug 24 05:41:46 2019 +0300 @@ -8025,12 +8025,6 @@ static njs_unit_test_t njs_test[] = { njs_str("(function(){return arguments[3];}).bind(null, 0)('a','b','c')"), njs_str("c") }, - { njs_str("(function(){return arguments.callee;})()"), - njs_str("TypeError: \"caller\", \"callee\" properties may not be accessed") }, - - { njs_str("(function(){return arguments.caller;})()"), - njs_str("TypeError: \"caller\", \"callee\" properties may not be accessed") }, - { njs_str("function sum() { var args = Array.prototype.slice.call(arguments); " "return args.reduce(function(prev, curr) {return prev + curr})};" "[sum(1), sum(1,2), sum(1,2,3), sum(1,2,3,4)]"), @@ -8041,6 +8035,39 @@ static njs_unit_test_t njs_test[] = "[concat('.',1,2,3), concat('+',1,2,3,4)]"), njs_str("1.2.3,1+2+3+4") }, + /* strict mode restrictions */ + + { njs_str("(function() {}).caller"), + njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") }, + + { njs_str("(function() {}).arguments"), + njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") }, + + { njs_str("var p = Object.getPrototypeOf(function() {});" + "var d = Object.getOwnPropertyDescriptor(p, 'caller');" + "typeof d.get == 'function' && typeof d.get == typeof d.set" + " && d.configurable && !d.enumerable"), + njs_str("true") }, + + { njs_str("var p = Object.getPrototypeOf(function() {});" + "var d = Object.getOwnPropertyDescriptor(p, 'arguments');" + "typeof d.get == 'function' && typeof d.get == typeof d.set" + " && d.configurable && !d.enumerable"), + njs_str("true") }, + + { njs_str("(function(){return arguments.callee;})()"), + njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") }, + + { njs_str("var f = function() { return arguments; };" + "Object.getOwnPropertyDescriptor(f(), 'caller')"), + njs_str("undefined") }, + + { njs_str("var f = function() { return arguments; };" + "var d = Object.getOwnPropertyDescriptor(f(), 'callee');" + "typeof d.get == 'function' && typeof d.get == typeof d.set" + " && !d.configurable && !d.enumerable"), + njs_str("true") }, + /* rest parameters. */ { njs_str("function myFoo(a,b,...other) { return other };" @@ -11487,6 +11514,8 @@ static njs_unit_test_t njs_test[] = "function isConfigurableMethods(o) {" " var except = [" " 'prototype'," + " 'caller'," + " 'arguments'," " ];" " return Object.getOwnPropertyNames(o)" " .filter(v => !except.includes(v)" @@ -11516,6 +11545,8 @@ static njs_unit_test_t njs_test[] = "function isWritableMethods(o) {" " var except = [" " 'prototype'," + " 'caller'," + " 'arguments'," " ];" " return Object.getOwnPropertyNames(o)" " .filter(v => !except.includes(v)" @@ -13939,6 +13970,8 @@ static njs_unit_test_t njs_test[] = " var except = [" " 'prototype'," " 'constructor'," + " 'caller'," + " 'arguments'," " ];" " return Object.getOwnPropertyNames(o)" " .filter(v => !except.includes(v)" From xeioex at nginx.com Fri Oct 18 14:00:09 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 18 Oct 2019 14:00:09 +0000 Subject: [njs] Avoiding OBJECT COPY instruction each time global object accessed. Message-ID: details: https://hg.nginx.org/njs/rev/10c10102cad0 branches: changeset: 1187:10c10102cad0 user: Dmitry Volyntsev date: Fri Oct 18 16:28:16 2019 +0300 description: Avoiding OBJECT COPY instruction each time global object accessed. diffstat: src/njs_builtin.c | 8 +++++++- src/njs_generator.c | 8 +++++--- src/njs_lexer.h | 4 ++-- src/njs_parser_terminal.c | 11 +++-------- src/njs_vm.c | 5 ++++- src/njs_vm.h | 10 ++++++++-- 6 files changed, 29 insertions(+), 17 deletions(-) diffs (151 lines): diff -r ed4472f545a1 -r 10c10102cad0 src/njs_builtin.c --- a/src/njs_builtin.c Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_builtin.c Fri Oct 18 16:28:16 2019 +0300 @@ -495,7 +495,7 @@ njs_prototype_function(njs_vm_t *vm, njs */ njs_int_t -njs_builtin_objects_clone(njs_vm_t *vm) +njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global) { size_t size; njs_uint_t i; @@ -531,6 +531,12 @@ njs_builtin_objects_clone(njs_vm_t *vm) vm->constructors[i].object.__proto__ = function_prototype; } + vm->global_object = vm->shared->objects[0]; + vm->global_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + vm->global_object.shared = 0; + + njs_set_object(global, &vm->global_object); + vm->string_object = vm->shared->string_object; vm->string_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object; diff -r ed4472f545a1 -r 10c10102cad0 src/njs_generator.c --- a/src/njs_generator.c Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_generator.c Fri Oct 18 16:28:16 2019 +0300 @@ -442,9 +442,9 @@ njs_generate(njs_vm_t *vm, njs_generator case NJS_TOKEN_NON_LOCAL_THIS: return njs_generate_name(vm, generator, node); - case NJS_TOKEN_GLOBAL_THIS: + case NJS_TOKEN_GLOBAL_OBJECT: if (vm->options.module) { - node->index = njs_value_index(vm, &node->u.value, + node->index = njs_value_index(vm, &njs_value_undefined, generator->runtime); if (njs_fast_path(node->index != NJS_INDEX_NONE)) { return NJS_OK; @@ -453,7 +453,9 @@ njs_generate(njs_vm_t *vm, njs_generator return NJS_ERROR; } - /* Fall through. */ + node->index = NJS_INDEX_GLOBAL_OBJECT; + + return NJS_OK; case NJS_TOKEN_NJS: case NJS_TOKEN_PROCESS: diff -r ed4472f545a1 -r 10c10102cad0 src/njs_lexer.h --- a/src/njs_lexer.h Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_lexer.h Fri Oct 18 16:28:16 2019 +0300 @@ -170,9 +170,9 @@ typedef enum { NJS_TOKEN_NON_LOCAL_THIS, NJS_TOKEN_ARGUMENTS, -#define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_THIS +#define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_OBJECT - NJS_TOKEN_GLOBAL_THIS, + NJS_TOKEN_GLOBAL_OBJECT, NJS_TOKEN_NJS, NJS_TOKEN_PROCESS, NJS_TOKEN_MATH, diff -r ed4472f545a1 -r 10c10102cad0 src/njs_parser_terminal.c --- a/src/njs_parser_terminal.c Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_parser_terminal.c Fri Oct 18 16:28:16 2019 +0300 @@ -261,14 +261,9 @@ njs_parser_reference(njs_vm_t *vm, njs_p break; } - node->token = NJS_TOKEN_GLOBAL_THIS; + node->token = NJS_TOKEN_GLOBAL_OBJECT; - if (vm->options.module) { - njs_set_undefined(&node->u.value); - break; - } - - /* Fall through. */ + break; case NJS_TOKEN_NJS: case NJS_TOKEN_PROCESS: @@ -652,7 +647,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars if (name.length == 0 || lexer->prev_token == NJS_TOKEN_THIS - || lexer->prev_token == NJS_TOKEN_GLOBAL_THIS) + || lexer->prev_token == NJS_TOKEN_GLOBAL_OBJECT) { return NJS_TOKEN_ILLEGAL; } diff -r ed4472f545a1 -r 10c10102cad0 src/njs_vm.c --- a/src/njs_vm.c Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_vm.c Fri Oct 18 16:28:16 2019 +0300 @@ -326,6 +326,7 @@ njs_vm_init(njs_vm_t *vm) u_char *values; njs_int_t ret; njs_arr_t *backtrace; + njs_value_t *global; njs_frame_t *frame; scope_size = vm->scope_size + NJS_INDEX_GLOBAL_OFFSET; @@ -362,7 +363,9 @@ njs_vm_init(njs_vm_t *vm) return NJS_ERROR; } - ret = njs_builtin_objects_clone(vm); + global = (njs_value_t *) (values + NJS_INDEX_GLOBAL_OBJECT_OFFSET); + + ret = njs_builtin_objects_clone(vm, global); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r ed4472f545a1 -r 10c10102cad0 src/njs_vm.h --- a/src/njs_vm.h Sat Aug 24 05:41:46 2019 +0300 +++ b/src/njs_vm.h Fri Oct 18 16:28:16 2019 +0300 @@ -203,7 +203,12 @@ enum njs_function_e { #define NJS_INDEX_OBJECT_MEMORY_ERROR \ njs_global_scope_index(NJS_CONSTRUCTOR_MEMORY_ERROR) -#define NJS_INDEX_GLOBAL_RETVAL njs_global_scope_index(NJS_CONSTRUCTOR_MAX) +#define NJS_INDEX_GLOBAL_OBJECT njs_global_scope_index(NJS_CONSTRUCTOR_MAX) +#define NJS_INDEX_GLOBAL_OBJECT_OFFSET \ + njs_scope_index(NJS_CONSTRUCTOR_MAX, 0) + +#define NJS_INDEX_GLOBAL_RETVAL \ + njs_global_scope_index(NJS_CONSTRUCTOR_MAX + 1) #define NJS_INDEX_GLOBAL_OFFSET njs_scope_index(NJS_CONSTRUCTOR_MAX + 1, 0) @@ -284,6 +289,7 @@ struct njs_vm_s { njs_object_t memory_error_object; njs_object_t string_object; + njs_object_t global_object; njs_arr_t *codes; /* of njs_vm_code_t */ @@ -341,7 +347,7 @@ void njs_vm_scopes_restore(njs_vm_t *vm, njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame); njs_int_t njs_builtin_objects_create(njs_vm_t *vm); -njs_int_t njs_builtin_objects_clone(njs_vm_t *vm); +njs_int_t njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global); njs_int_t njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, njs_str_t *name); From xeioex at nginx.com Fri Oct 18 14:00:10 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 18 Oct 2019 14:00:10 +0000 Subject: [njs] Querying global object when variable cannot be resolved. Message-ID: details: https://hg.nginx.org/njs/rev/5f192dbb694e branches: changeset: 1188:5f192dbb694e user: Dmitry Volyntsev date: Fri Oct 18 16:34:50 2019 +0300 description: Querying global object when variable cannot be resolved. diffstat: src/njs_disassembler.c | 2 + src/njs_generator.c | 97 ++++++++++++++++++++++++++++++++++------------- src/njs_vmcode.c | 17 ++++++++ src/njs_vmcode.h | 1 + src/test/njs_unit_test.c | 22 ++++++++++ 5 files changed, 111 insertions(+), 28 deletions(-) diffs (285 lines): diff -r 10c10102cad0 -r 5f192dbb694e src/njs_disassembler.c --- a/src/njs_disassembler.c Fri Oct 18 16:28:16 2019 +0300 +++ b/src/njs_disassembler.c Fri Oct 18 16:34:50 2019 +0300 @@ -34,6 +34,8 @@ static njs_code_name_t code_names[] = { { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t), njs_str("PROP GET ") }, + { NJS_VMCODE_GLOBAL_GET, sizeof(njs_vmcode_prop_get_t), + njs_str("GLOBAL GET ") }, { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t), njs_str("PROP INIT ") }, { NJS_VMCODE_PROTO_INIT, sizeof(njs_vmcode_prop_set_t), diff -r 10c10102cad0 -r 5f192dbb694e src/njs_generator.c --- a/src/njs_generator.c Fri Oct 18 16:28:16 2019 +0300 +++ b/src/njs_generator.c Fri Oct 18 16:34:50 2019 +0300 @@ -62,7 +62,7 @@ static njs_int_t njs_generate_name(njs_v static njs_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node); + njs_parser_node_t *node, njs_reference_type_t type); static njs_int_t njs_generate_var_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_if_statement(njs_vm_t *vm, @@ -176,6 +176,8 @@ static njs_int_t njs_generate_node_index njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator, njs_index_t index); +static njs_int_t njs_generate_global_reference(njs_vm_t *vm, + njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception); static njs_int_t njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); @@ -577,11 +579,8 @@ njs_generate_name(njs_vm_t *vm, njs_gene njs_vmcode_object_copy_t *copy; var = njs_variable_resolve(vm, node); - if (njs_slow_path(var == NULL)) { - return njs_generate_reference_error(vm, generator, node); - } - - if (var->type == NJS_VARIABLE_FUNCTION) { + + if (var != NULL && var->type == NJS_VARIABLE_FUNCTION) { node->index = njs_generate_dest_index(vm, generator, node); if (njs_slow_path(node->index == NJS_INDEX_ERROR)) { @@ -596,7 +595,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene return NJS_OK; } - return njs_generate_variable(vm, generator, node); + return njs_generate_variable(vm, generator, node, NJS_REFERENCE); } @@ -628,13 +627,22 @@ njs_generate_builtin_object(njs_vm_t *vm static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node) + njs_parser_node_t *node, njs_reference_type_t type) { njs_index_t index; index = njs_variable_index(vm, node); if (njs_slow_path(index == NJS_INDEX_NONE)) { - return njs_generate_reference_error(vm, generator, node); + + switch (type) { + case NJS_DECLARATION: + return njs_generate_reference_error(vm, generator, node); + + case NJS_REFERENCE: + case NJS_TYPEOF: + return njs_generate_global_reference(vm, generator, node, + type == NJS_REFERENCE); + } } node->index = index; @@ -1682,7 +1690,7 @@ njs_generate_assignment(njs_vm_t *vm, nj if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -1805,7 +1813,7 @@ njs_generate_operation_assignment(njs_vm if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2239,17 +2247,9 @@ njs_generate_typeof_operation(njs_vm_t * expr = node->left; if (expr->token == NJS_TOKEN_NAME) { - expr->index = njs_variable_typeof(vm, expr); - - if (expr->u.reference.variable) { - ret = njs_generate_variable(vm, generator, expr); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - } else { - expr->index = njs_value_index(vm, &njs_value_undefined, - generator->runtime); + ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; } } else { @@ -2291,7 +2291,7 @@ njs_generate_inc_dec_operation(njs_vm_t if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2668,7 +2668,7 @@ njs_generate_function_call(njs_vm_t *vm, name = node->left; } else { - ret = njs_generate_variable(vm, generator, node); + ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2676,10 +2676,6 @@ njs_generate_function_call(njs_vm_t *vm, name = node; } - if (node->u.reference.not_defined) { - return NJS_OK; - } - njs_generate_code(generator, njs_vmcode_function_frame_t, func, NJS_VMCODE_FUNCTION_FRAME, 2); func_offset = njs_code_offset(generator, func); @@ -3361,6 +3357,51 @@ njs_generate_index_release(njs_vm_t *vm, static njs_int_t +njs_generate_global_reference(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node, njs_bool_t exception) +{ + njs_str_t *name; + njs_int_t ret; + njs_index_t index; + njs_value_t property; + njs_vmcode_prop_get_t *prop_get; + + index = njs_generate_dest_index(vm, generator, node); + if (njs_slow_path(index == NJS_INDEX_ERROR)) { + return NJS_ERROR; + } + + njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get, + exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET, 3); + + prop_get->value = index; + prop_get->object = NJS_INDEX_GLOBAL_OBJECT; + + /* FIXME: cache keys in a hash. */ + + name = &node->u.reference.name; + + ret = njs_string_set(vm, &property, name->start, name->length); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + prop_get->property = njs_value_index(vm, &property, generator->runtime); + if (njs_slow_path(prop_get->property == NJS_INDEX_NONE)) { + return NJS_ERROR; + } + + node->index = index; + + if (!exception) { + return NJS_OK; + } + + return njs_generate_reference_error(vm, generator, node); +} + + +static njs_int_t njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) { diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.c --- a/src/njs_vmcode.c Fri Oct 18 16:28:16 2019 +0300 +++ b/src/njs_vmcode.c Fri Oct 18 16:34:50 2019 +0300 @@ -209,6 +209,23 @@ next: pc += sizeof(njs_vmcode_3addr_t); goto next; + case NJS_VMCODE_GLOBAL_GET: + get = (njs_vmcode_prop_get_t *) pc; + retval = njs_vmcode_operand(vm, get->value); + + ret = njs_value_property(vm, value1, value2, retval); + if (njs_slow_path(ret == NJS_ERROR)) { + goto error; + } + + pc += sizeof(njs_vmcode_prop_get_t); + + if (ret == NJS_OK) { + pc += sizeof(njs_vmcode_reference_error_t); + } + + goto next; + /* * njs_vmcode_try_return() saves a return value to use it later by * njs_vmcode_finally(), and jumps to the nearest try_break block. diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.h --- a/src/njs_vmcode.h Fri Oct 18 16:28:16 2019 +0300 +++ b/src/njs_vmcode.h Fri Oct 18 16:34:50 2019 +0300 @@ -72,6 +72,7 @@ typedef uint8_t #define NJS_VMCODE_DECREMENT VMCODE1(4) #define NJS_VMCODE_POST_DECREMENT VMCODE1(5) #define NJS_VMCODE_TRY_RETURN VMCODE1(6) +#define NJS_VMCODE_GLOBAL_GET VMCODE1(7) #define NJS_VMCODE_LESS VMCODE1(8) #define NJS_VMCODE_GREATER VMCODE1(9) diff -r 10c10102cad0 -r 5f192dbb694e src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Oct 18 16:28:16 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 18 16:34:50 2019 +0300 @@ -2694,6 +2694,10 @@ static njs_unit_test_t njs_test[] = "}; t"), njs_str("A") }, + { njs_str("[isNaN, undefined, isFinite]." + "map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"), + njs_str("1,0,0") }, + /* continue. */ { njs_str("continue"), @@ -9319,6 +9323,18 @@ static njs_unit_test_t njs_test[] = { njs_str("this.a = 1; this.a"), njs_str("1") }, + { njs_str("this.a = 1; a"), + njs_str("1") }, + + { njs_str("this.a = 2; this.b = 3; a * b - a"), + njs_str("4") }, + + { njs_str("this.a = 1; a()"), + njs_str("TypeError: number is not a function") }, + + { njs_str("this.a = ()=>1; a()"), + njs_str("1") }, + { njs_str("this.undefined = 42"), njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") }, @@ -13084,6 +13100,12 @@ static njs_unit_test_t njs_test[] = { njs_str("isNaN.length"), njs_str("1") }, + { njs_str("typeof isNaN"), + njs_str("function") }, + + { njs_str("typeof isNaN.length"), + njs_str("number") }, + { njs_str("isNaN()"), njs_str("true") }, From xeioex at nginx.com Fri Oct 18 14:00:10 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 18 Oct 2019 14:00:10 +0000 Subject: [njs] Moving global functions to global object. Message-ID: details: https://hg.nginx.org/njs/rev/c86310ffb38a branches: changeset: 1189:c86310ffb38a user: Dmitry Volyntsev date: Fri Oct 18 16:38:55 2019 +0300 description: Moving global functions to global object. This closes #132 issue on Github. diffstat: src/njs_builtin.c | 217 +++++++++++++++++++++++++++---------------- src/njs_generator.c | 15 +-- src/njs_lexer.h | 18 +--- src/njs_lexer_keyword.c | 19 +--- src/njs_module.c | 7 - src/njs_module.h | 1 - src/njs_number.c | 80 ---------------- src/njs_number.h | 5 - src/njs_parser.c | 4 +- src/njs_parser.h | 4 + src/njs_parser_expression.c | 2 +- src/njs_parser_terminal.c | 27 +----- src/njs_string.c | 135 --------------------------- src/njs_string.h | 6 - src/njs_timer.c | 20 ---- src/njs_timer.h | 4 - src/njs_vm.h | 21 +---- src/test/njs_unit_test.c | 31 ++++++ 18 files changed, 181 insertions(+), 435 deletions(-) diffs (893 lines): diff -r 5f192dbb694e -r c86310ffb38a src/njs_builtin.c --- a/src/njs_builtin.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_builtin.c Fri Oct 18 16:38:55 2019 +0300 @@ -93,47 +93,6 @@ const njs_object_init_t *njs_constructo }; -const njs_object_init_t *njs_function_init[] = { - &njs_eval_function_init, - &njs_to_string_function_init, - &njs_is_nan_function_init, - &njs_is_finite_function_init, - &njs_parse_int_function_init, - &njs_parse_float_function_init, - &njs_encode_uri_function_init, - &njs_encode_uri_component_function_init, - &njs_decode_uri_function_init, - &njs_decode_uri_component_function_init, - &njs_require_function_init, - &njs_set_timeout_function_init, - &njs_set_immediate_function_init, - &njs_clear_timeout_function_init, - NULL -}; - - -const njs_function_init_t njs_native_functions[] = { - /* SunC does not allow empty array initialization. */ - { njs_eval_function, { 0 } }, - { njs_object_prototype_to_string, { 0 } }, - { njs_number_global_is_nan, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_number_is_finite, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_number_parse_int, - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } }, - { njs_number_parse_float, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_encode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_decode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_decode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_set_timeout, - { NJS_SKIP_ARG, NJS_FUNCTION_ARG, NJS_NUMBER_ARG } }, - { njs_set_immediate, - { NJS_SKIP_ARG, NJS_FUNCTION_ARG } }, - { njs_clear_timeout, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, -}; - - const njs_function_init_t njs_native_constructors[] = { /* SunC does not allow empty array initialization. */ { njs_object_constructor, { 0 } }, @@ -331,29 +290,6 @@ njs_builtin_objects_create(njs_vm_t *vm) } } - f = njs_native_functions; - func = shared->functions; - - for (p = njs_function_init; *p != NULL; p++) { - obj = *p; - - ret = njs_object_hash_init(vm, &func->object.shared_hash, obj); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - func->object.shared = 1; - func->object.extensible = 1; - func->native = 1; - func->args_offset = 1; - - func->u.native = f->native; - memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); - - f++; - func++; - } - prototype = shared->prototypes; memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); @@ -994,28 +930,21 @@ njs_int_t njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, njs_str_t *name) { - size_t len; - njs_str_t string, middle; - njs_int_t ret; - const njs_object_init_t *obj, **p; - const njs_object_prop_t *prop; - const njs_function_init_t *fun; - - fun = njs_native_functions; - - for (p = njs_function_init; *p != NULL; p++, fun++) { - if (function->u.native == fun->native) { - *name = (*p)->name; - - return NJS_OK; - } - } + size_t len; + njs_str_t string, middle; + njs_int_t ret; + const njs_object_init_t *obj; + const njs_object_prop_t *prop; middle = njs_str_value("."); ret = njs_builtin_match(njs_object_init, function, &prop, &obj); if (ret == NJS_OK) { + if (!obj->name.length) { + middle = njs_str_value(""); + } + goto found; } @@ -1100,11 +1029,137 @@ static const njs_object_prop_t njs_glob .name = njs_string("undefined"), .value = njs_value(NJS_UNDEFINED, 0, NAN), }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isFinite"), + .value = njs_native_function(njs_number_is_finite, 1, + NJS_SKIP_ARG, NJS_NUMBER_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isNaN"), + .value = njs_native_function(njs_number_global_is_nan, 1, + NJS_SKIP_ARG, NJS_NUMBER_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("parseFloat"), + .value = njs_native_function(njs_number_parse_float, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("parseInt"), + .value = njs_native_function(njs_number_parse_int, 2, + NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("toString"), + .value = njs_native_function(njs_object_prototype_to_string, 0, 0), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("encodeURI"), + .value = njs_native_function(njs_string_encode_uri, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_long_string("encodeURIComponent"), + .value = njs_native_function(njs_string_encode_uri_component, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("decodeURI"), + .value = njs_native_function(njs_string_decode_uri, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_long_string("decodeURIComponent"), + .value = njs_native_function(njs_string_decode_uri_component, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("eval"), + .value = njs_native_function(njs_eval_function, 1, 0), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("setTimeout"), + .value = njs_native_function(njs_set_timeout, 2, + NJS_SKIP_ARG, NJS_FUNCTION_ARG, + NJS_NUMBER_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("setImmediate"), + .value = njs_native_function(njs_set_immediate, 4, + NJS_SKIP_ARG, NJS_FUNCTION_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("clearTimeout"), + .value = njs_native_function(njs_clear_timeout, 1, + NJS_SKIP_ARG, NJS_NUMBER_ARG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("require"), + .value = njs_native_function(njs_module_require, 1, + NJS_SKIP_ARG, NJS_STRING_ARG), + .writable = 1, + .configurable = 1, + }, + }; const njs_object_init_t njs_global_this_init = { - njs_str("this"), + njs_str(""), njs_global_this_object_properties, njs_nitems(njs_global_this_object_properties) }; diff -r 5f192dbb694e -r c86310ffb38a src/njs_generator.c --- a/src/njs_generator.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_generator.c Fri Oct 18 16:38:55 2019 +0300 @@ -441,6 +441,7 @@ njs_generate(njs_vm_t *vm, njs_generator case NJS_TOKEN_NAME: case NJS_TOKEN_ARGUMENTS: + case NJS_TOKEN_EVAL: case NJS_TOKEN_NON_LOCAL_THIS: return njs_generate_name(vm, generator, node); @@ -463,20 +464,6 @@ njs_generate(njs_vm_t *vm, njs_generator case NJS_TOKEN_PROCESS: case NJS_TOKEN_MATH: case NJS_TOKEN_JSON: - case NJS_TOKEN_EVAL: - case NJS_TOKEN_TO_STRING: - case NJS_TOKEN_IS_NAN: - case NJS_TOKEN_IS_FINITE: - case NJS_TOKEN_PARSE_INT: - case NJS_TOKEN_PARSE_FLOAT: - case NJS_TOKEN_ENCODE_URI: - case NJS_TOKEN_ENCODE_URI_COMPONENT: - case NJS_TOKEN_DECODE_URI: - case NJS_TOKEN_DECODE_URI_COMPONENT: - case NJS_TOKEN_REQUIRE: - case NJS_TOKEN_SET_TIMEOUT: - case NJS_TOKEN_SET_IMMEDIATE: - case NJS_TOKEN_CLEAR_TIMEOUT: return njs_generate_builtin_object(vm, generator, node); case NJS_TOKEN_FUNCTION: diff -r 5f192dbb694e -r c86310ffb38a src/njs_lexer.h --- a/src/njs_lexer.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_lexer.h Fri Oct 18 16:38:55 2019 +0300 @@ -169,6 +169,7 @@ typedef enum { NJS_TOKEN_THIS, NJS_TOKEN_NON_LOCAL_THIS, NJS_TOKEN_ARGUMENTS, + NJS_TOKEN_EVAL, #define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_OBJECT @@ -196,23 +197,6 @@ typedef enum { NJS_TOKEN_URI_ERROR_CONSTRUCTOR, NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, -#define NJS_TOKEN_FIRST_FUNCTION NJS_TOKEN_EVAL - - NJS_TOKEN_EVAL, - NJS_TOKEN_TO_STRING, - NJS_TOKEN_IS_NAN, - NJS_TOKEN_IS_FINITE, - NJS_TOKEN_PARSE_INT, - NJS_TOKEN_PARSE_FLOAT, - NJS_TOKEN_ENCODE_URI, - NJS_TOKEN_ENCODE_URI_COMPONENT, - NJS_TOKEN_DECODE_URI, - NJS_TOKEN_DECODE_URI_COMPONENT, - NJS_TOKEN_REQUIRE, - NJS_TOKEN_SET_TIMEOUT, - NJS_TOKEN_SET_IMMEDIATE, - NJS_TOKEN_CLEAR_TIMEOUT, - NJS_TOKEN_IMPORT, NJS_TOKEN_EXPORT, diff -r 5f192dbb694e -r c86310ffb38a src/njs_lexer_keyword.c --- a/src/njs_lexer_keyword.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_lexer_keyword.c Fri Oct 18 16:38:55 2019 +0300 @@ -53,7 +53,6 @@ static const njs_keyword_t njs_keywords /* Builtin objects. */ { njs_str("this"), NJS_TOKEN_THIS, 0 }, - { njs_str("arguments"), NJS_TOKEN_ARGUMENTS, 0 }, { njs_str("njs"), NJS_TOKEN_NJS, 0 }, { njs_str("process"), NJS_TOKEN_PROCESS, 0 }, { njs_str("Math"), NJS_TOKEN_MATH, 0 }, @@ -79,27 +78,15 @@ static const njs_keyword_t njs_keywords { njs_str("URIError"), NJS_TOKEN_URI_ERROR_CONSTRUCTOR, 0 }, { njs_str("MemoryError"), NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, 0 }, - { njs_str("eval"), NJS_TOKEN_EVAL, 0 }, - { njs_str("toString"), NJS_TOKEN_TO_STRING, 0 }, - { njs_str("isNaN"), NJS_TOKEN_IS_NAN, 0 }, - { njs_str("isFinite"), NJS_TOKEN_IS_FINITE, 0 }, - { njs_str("parseInt"), NJS_TOKEN_PARSE_INT, 0 }, - { njs_str("parseFloat"), NJS_TOKEN_PARSE_FLOAT, 0 }, - { njs_str("encodeURI"), NJS_TOKEN_ENCODE_URI, 0 }, - { njs_str("encodeURIComponent"), NJS_TOKEN_ENCODE_URI_COMPONENT, 0 }, - { njs_str("decodeURI"), NJS_TOKEN_DECODE_URI, 0 }, - { njs_str("decodeURIComponent"), NJS_TOKEN_DECODE_URI_COMPONENT, 0 }, - { njs_str("require"), NJS_TOKEN_REQUIRE, 0 }, - { njs_str("setTimeout"), NJS_TOKEN_SET_TIMEOUT, 0 }, - { njs_str("setImmediate"), NJS_TOKEN_SET_IMMEDIATE, 0 }, - { njs_str("clearTimeout"), NJS_TOKEN_CLEAR_TIMEOUT, 0 }, - /* Module. */ { njs_str("import"), NJS_TOKEN_IMPORT, 0 }, { njs_str("export"), NJS_TOKEN_EXPORT, 0 }, /* Reserved words. */ + { njs_str("arguments"), NJS_TOKEN_ARGUMENTS, 0 }, + { njs_str("eval"), NJS_TOKEN_EVAL, 0 }, + { njs_str("await"), NJS_TOKEN_RESERVED, 0 }, { njs_str("class"), NJS_TOKEN_RESERVED, 0 }, { njs_str("const"), NJS_TOKEN_RESERVED, 0 }, diff -r 5f192dbb694e -r c86310ffb38a src/njs_module.c --- a/src/njs_module.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_module.c Fri Oct 18 16:38:55 2019 +0300 @@ -541,10 +541,3 @@ njs_module_require(njs_vm_t *vm, njs_val return NJS_ERROR; } - - -const njs_object_init_t njs_require_function_init = { - njs_str("require"), - NULL, - 0, -}; diff -r 5f192dbb694e -r c86310ffb38a src/njs_module.h --- a/src/njs_module.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_module.h Fri Oct 18 16:38:55 2019 +0300 @@ -24,7 +24,6 @@ njs_int_t njs_module_require(njs_vm_t *v extern const njs_lvlhsh_proto_t njs_modules_hash_proto; -extern const njs_object_init_t njs_require_function_init; #endif /* _NJS_MODULE_H_INCLUDED_ */ diff -r 5f192dbb694e -r c86310ffb38a src/njs_number.c --- a/src/njs_number.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_number.c Fri Oct 18 16:38:55 2019 +0300 @@ -1062,33 +1062,6 @@ njs_number_parse_float(njs_vm_t *vm, njs } -static const njs_object_prop_t njs_is_nan_function_properties[] = -{ - /* isNaN.name == "isNaN". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("isNaN"), - .configurable = 1, - }, - - /* isNaN.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_is_nan_function_init = { - njs_str("isNaN"), - njs_is_nan_function_properties, - njs_nitems(njs_is_nan_function_properties), -}; - - static const njs_object_prop_t njs_is_finite_function_properties[] = { /* isFinite.name == "isFinite". */ @@ -1115,56 +1088,3 @@ const njs_object_init_t njs_is_finite_f njs_nitems(njs_is_finite_function_properties), }; - -static const njs_object_prop_t njs_parse_int_function_properties[] = -{ - /* parseInt.name == "parseInt". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("parseInt"), - .configurable = 1, - }, - - /* parseInt.length == 2. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 2.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_parse_int_function_init = { - njs_str("parseInt"), - njs_parse_int_function_properties, - njs_nitems(njs_parse_int_function_properties), -}; - - -static const njs_object_prop_t njs_parse_float_function_properties[] = -{ - /* parseFloat.name == "parseFloat". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("parseFloat"), - .configurable = 1, - }, - - /* parseFloat.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_parse_float_function_init = { - njs_str("parseFloat"), - njs_parse_float_function_properties, - njs_nitems(njs_parse_float_function_properties), -}; diff -r 5f192dbb694e -r c86310ffb38a src/njs_number.h --- a/src/njs_number.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_number.h Fri Oct 18 16:38:55 2019 +0300 @@ -186,10 +186,5 @@ njs_uint32_to_string(njs_value_t *value, extern const njs_object_init_t njs_number_constructor_init; extern const njs_object_init_t njs_number_prototype_init; -extern const njs_object_init_t njs_is_nan_function_init; -extern const njs_object_init_t njs_is_finite_function_init; -extern const njs_object_init_t njs_parse_int_function_init; -extern const njs_object_init_t njs_parse_float_function_init; - #endif /* _NJS_NUMBER_H_INCLUDED_ */ diff -r 5f192dbb694e -r c86310ffb38a src/njs_parser.c --- a/src/njs_parser.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_parser.c Fri Oct 18 16:38:55 2019 +0300 @@ -636,7 +636,7 @@ njs_parser_function_declaration(njs_vm_t } if (token != NJS_TOKEN_NAME) { - if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) { + if (njs_parser_restricted_identifier(token)) { njs_parser_syntax_error(vm, parser, "Identifier \"%V\" " "is forbidden in function declaration", njs_parser_text(parser)); @@ -1034,7 +1034,7 @@ njs_parser_var_statement(njs_vm_t *vm, n } if (token != NJS_TOKEN_NAME) { - if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) { + if (njs_parser_restricted_identifier(token)) { njs_parser_syntax_error(vm, parser, "Identifier \"%V\" " "is forbidden in var declaration", njs_parser_text(parser)); diff -r 5f192dbb694e -r c86310ffb38a src/njs_parser.h --- a/src/njs_parser.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_parser.h Fri Oct 18 16:38:55 2019 +0300 @@ -126,6 +126,10 @@ void njs_parser_node_error(njs_vm_t *vm, #define njs_parser_leave(parser) ((parser)->count--) +#define njs_parser_restricted_identifier(token) \ + (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) + + #define njs_parser_is_lvalue(node) \ ((node)->token == NJS_TOKEN_NAME || (node)->token == NJS_TOKEN_PROPERTY) diff -r 5f192dbb694e -r c86310ffb38a src/njs_parser_expression.c --- a/src/njs_parser_expression.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_parser_expression.c Fri Oct 18 16:38:55 2019 +0300 @@ -310,7 +310,7 @@ njs_parser_assignment_expression(njs_vm_ if (!njs_parser_is_lvalue(parser->node)) { token = parser->node->token; - if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) { + if (njs_parser_restricted_identifier(token)) { njs_parser_syntax_error(vm, parser, "Identifier \"%s\" " "is forbidden as left-hand in assignment", (token == NJS_TOKEN_EVAL) ? "eval" diff -r 5f192dbb694e -r c86310ffb38a src/njs_parser_terminal.c --- a/src/njs_parser_terminal.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_parser_terminal.c Fri Oct 18 16:38:55 2019 +0300 @@ -344,27 +344,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p node->index = NJS_INDEX_OBJECT_MEMORY_ERROR; break; - case NJS_TOKEN_EVAL: - case NJS_TOKEN_TO_STRING: - case NJS_TOKEN_IS_NAN: - case NJS_TOKEN_IS_FINITE: - case NJS_TOKEN_PARSE_INT: - case NJS_TOKEN_PARSE_FLOAT: - case NJS_TOKEN_ENCODE_URI: - case NJS_TOKEN_ENCODE_URI_COMPONENT: - case NJS_TOKEN_DECODE_URI: - case NJS_TOKEN_DECODE_URI_COMPONENT: - case NJS_TOKEN_REQUIRE: - case NJS_TOKEN_SET_TIMEOUT: - case NJS_TOKEN_SET_IMMEDIATE: - case NJS_TOKEN_CLEAR_TIMEOUT: - ret = njs_parser_builtin(vm, parser, node, NJS_FUNCTION, name, hash); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - - break; - case NJS_TOKEN_ARGUMENTS: njs_thread_log_debug("JS: arguments"); @@ -395,6 +374,7 @@ njs_parser_reference(njs_vm_t *vm, njs_p break; case NJS_TOKEN_NAME: + case NJS_TOKEN_EVAL: njs_thread_log_debug("JS: %V", name); node->token_line = token_line; @@ -448,11 +428,6 @@ njs_parser_builtin(njs_vm_t *vm, njs_par njs_set_object(&var->value, &vm->shared->objects[index]); break; - case NJS_FUNCTION: - index = node->token - NJS_TOKEN_FIRST_FUNCTION; - njs_set_function(&var->value, &vm->shared->functions[index]); - break; - default: return NJS_ERROR; } diff -r 5f192dbb694e -r c86310ffb38a src/njs_string.c --- a/src/njs_string.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_string.c Fri Oct 18 16:38:55 2019 +0300 @@ -4857,138 +4857,3 @@ njs_value_index(njs_vm_t *vm, const njs_ return (njs_index_t) value; } - - -static const njs_object_prop_t njs_to_string_function_properties[] = -{ - /* toString.name == "toString". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("toString"), - .configurable = 1, - }, - - /* toString.length == 0. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 0, 0.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_to_string_function_init = { - njs_str("toString"), - njs_to_string_function_properties, - njs_nitems(njs_to_string_function_properties), -}; - - -static const njs_object_prop_t njs_encode_uri_function_properties[] = -{ - /* encodeURI.name == "encodeURI". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("encodeURI"), - .configurable = 1, - }, - - /* encodeURI.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_encode_uri_function_init = { - njs_str("encodeURI"), - njs_encode_uri_function_properties, - njs_nitems(njs_encode_uri_function_properties), -}; - - -static const njs_object_prop_t njs_encode_uri_component_function_properties[] = -{ - /* encodeURIComponent.name == "encodeURIComponent". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_long_string("encodeURIComponent"), - .configurable = 1, - }, - - /* encodeURIComponent.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_encode_uri_component_function_init = { - njs_str("encodeURIComponent"), - njs_encode_uri_component_function_properties, - njs_nitems(njs_encode_uri_component_function_properties), -}; - - -static const njs_object_prop_t njs_decode_uri_function_properties[] = -{ - /* decodeURI.name == "decodeURI". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("decodeURI"), - .configurable = 1, - }, - - /* decodeURI.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_decode_uri_function_init = { - njs_str("decodeURI"), - njs_decode_uri_function_properties, - njs_nitems(njs_decode_uri_function_properties), -}; - - -static const njs_object_prop_t njs_decode_uri_component_function_properties[] = -{ - /* decodeURIComponent.name == "decodeURIComponent". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_long_string("decodeURIComponent"), - .configurable = 1, - }, - - /* decodeURIComponent.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_decode_uri_component_function_init = { - njs_str("decodeURIComponent"), - njs_decode_uri_component_function_properties, - njs_nitems(njs_decode_uri_component_function_properties), -}; diff -r 5f192dbb694e -r c86310ffb38a src/njs_string.h --- a/src/njs_string.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_string.h Fri Oct 18 16:38:55 2019 +0300 @@ -198,11 +198,5 @@ extern const njs_object_init_t njs_stri extern const njs_object_init_t njs_string_prototype_init; extern const njs_object_init_t njs_string_instance_init; -extern const njs_object_init_t njs_to_string_function_init; -extern const njs_object_init_t njs_encode_uri_function_init; -extern const njs_object_init_t njs_encode_uri_component_function_init; -extern const njs_object_init_t njs_decode_uri_function_init; -extern const njs_object_init_t njs_decode_uri_component_function_init; - #endif /* _NJS_STRING_H_INCLUDED_ */ diff -r 5f192dbb694e -r c86310ffb38a src/njs_timer.c --- a/src/njs_timer.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_timer.c Fri Oct 18 16:38:55 2019 +0300 @@ -127,23 +127,3 @@ njs_clear_timeout(njs_vm_t *vm, njs_valu return NJS_OK; } - - -const njs_object_init_t njs_set_timeout_function_init = { - njs_str("setTimeout"), - NULL, - 0, -}; - -const njs_object_init_t njs_set_immediate_function_init = { - njs_str("setImmediate"), - NULL, - 0, -}; - - -const njs_object_init_t njs_clear_timeout_function_init = { - njs_str("clearTimeout"), - NULL, - 0, -}; diff -r 5f192dbb694e -r c86310ffb38a src/njs_timer.h --- a/src/njs_timer.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_timer.h Fri Oct 18 16:38:55 2019 +0300 @@ -16,8 +16,4 @@ njs_int_t njs_clear_timeout(njs_vm_t *vm njs_uint_t nargs, njs_index_t unused); -extern const njs_object_init_t njs_set_timeout_function_init; -extern const njs_object_init_t njs_set_immediate_function_init; -extern const njs_object_init_t njs_clear_timeout_function_init; - #endif /* _NJS_TIMER_H_INCLUDED_ */ diff -r 5f192dbb694e -r c86310ffb38a src/njs_vm.h --- a/src/njs_vm.h Fri Oct 18 16:34:50 2019 +0300 +++ b/src/njs_vm.h Fri Oct 18 16:38:55 2019 +0300 @@ -144,31 +144,13 @@ enum njs_constructor_e { enum njs_object_e { NJS_OBJECT_THIS = 0, NJS_OBJECT_NJS, + NJS_OBJECT_PROCESS, NJS_OBJECT_MATH, NJS_OBJECT_JSON, #define NJS_OBJECT_MAX (NJS_OBJECT_JSON + 1) }; -enum njs_function_e { - NJS_FUNCTION_EVAL = 0, - NJS_FUNCTION_TO_STRING, - NJS_FUNCTION_IS_NAN, - NJS_FUNCTION_IS_FINITE, - NJS_FUNCTION_PARSE_INT, - NJS_FUNCTION_PARSE_FLOAT, - NJS_FUNCTION_STRING_ENCODE_URI, - NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT, - NJS_FUNCTION_STRING_DECODE_URI, - NJS_FUNCTION_STRING_DECODE_URI_COMPONENT, - NJS_FUNCTION_REQUIRE, - NJS_FUNCTION_SET_TIMEOUT, - NJS_FUNCTION_SET_IMMEDIATE, - NJS_FUNCTION_CLEAR_TIMEOUT, -#define NJS_FUNCTION_MAX (NJS_FUNCTION_CLEAR_TIMEOUT + 1) -}; - - #define njs_scope_index(value, type) \ ((njs_index_t) (((value) << NJS_SCOPE_SHIFT) | (type))) @@ -329,7 +311,6 @@ struct njs_vm_shared_s { njs_object_t string_object; njs_object_t objects[NJS_OBJECT_MAX]; - njs_function_t functions[NJS_FUNCTION_MAX]; /* * The prototypes and constructors arrays must be togther because they are diff -r 5f192dbb694e -r c86310ffb38a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Oct 18 16:34:50 2019 +0300 +++ b/src/test/njs_unit_test.c Fri Oct 18 16:38:55 2019 +0300 @@ -12137,6 +12137,13 @@ static njs_unit_test_t njs_test[] = { njs_str("eval()"), njs_str("InternalError: Not implemented") }, + { njs_str("delete this.eval; eval"), + njs_str("ReferenceError: \"eval\" is not defined in 1") }, + + { njs_str("var d = Object.getOwnPropertyDescriptor(this, 'eval');" + "d.writable && !d.enumerable && d.configurable"), + njs_str("true") }, + /* Math. */ { njs_str("Math.PI"), @@ -14025,6 +14032,18 @@ static njs_unit_test_t njs_test[] = { njs_str("require()"), njs_str("TypeError: missing path") }, + { njs_str("require.length"), + njs_str("1") }, + + { njs_str("require.name"), + njs_str("require") }, + + { njs_str("typeof require"), + njs_str("function") }, + + { njs_str("require.hasOwnProperty('length')"), + njs_str("true") }, + { njs_str("var fs = require('fs'); typeof fs"), njs_str("object") }, @@ -14474,6 +14493,18 @@ static njs_unit_test_t njs_shared_test[ { njs_str("import cr from 'crypto'; cr.createHash('md5')"), njs_str("[object Hash]") }, + + { njs_str("isFinite()"), + njs_str("false") }, + + { njs_str("Number.isFinite(function(){})"), + njs_str("false") }, + + { njs_str("isFin()"), + njs_str("ReferenceError: \"isFin\" is not defined in 1") }, + + { njs_str("isNaN(function(){})"), + njs_str("true") }, }; From xeioex at nginx.com Mon Oct 21 12:11:08 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 21 Oct 2019 12:11:08 +0000 Subject: [njs] Fixed keyword list. Message-ID: details: https://hg.nginx.org/njs/rev/f01ee3828b15 branches: changeset: 1190:f01ee3828b15 user: Dmitry Volyntsev date: Mon Oct 21 15:10:34 2019 +0300 description: Fixed keyword list. "undefined", "NaN" and "Infinity" are not keywords. This closes #219 issue on Github. diffstat: src/njs_builtin.c | 2 +- src/njs_generator.c | 1 - src/njs_lexer.h | 3 +- src/njs_lexer_keyword.c | 4 +-- src/njs_parser_expression.c | 1 - src/njs_parser_terminal.c | 6 ----- src/test/njs_unit_test.c | 54 ++++++++++++++++++++++++++++++++++++-------- 7 files changed, 47 insertions(+), 24 deletions(-) diffs (205 lines): diff -r c86310ffb38a -r f01ee3828b15 src/njs_builtin.c --- a/src/njs_builtin.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_builtin.c Mon Oct 21 15:10:34 2019 +0300 @@ -1021,7 +1021,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("Infinity"), - .value = njs_value(NJS_NUMBER, 0, INFINITY), + .value = njs_value(NJS_NUMBER, 1, INFINITY), }, { diff -r c86310ffb38a -r f01ee3828b15 src/njs_generator.c --- a/src/njs_generator.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_generator.c Mon Oct 21 15:10:34 2019 +0300 @@ -383,7 +383,6 @@ njs_generate(njs_vm_t *vm, njs_generator case NJS_TOKEN_POST_DECREMENT: return njs_generate_inc_dec_operation(vm, generator, node, 1); - case NJS_TOKEN_UNDEFINED: case NJS_TOKEN_NULL: case NJS_TOKEN_BOOLEAN: case NJS_TOKEN_NUMBER: diff -r c86310ffb38a -r f01ee3828b15 src/njs_lexer.h --- a/src/njs_lexer.h Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_lexer.h Mon Oct 21 15:10:34 2019 +0300 @@ -106,9 +106,8 @@ typedef enum { NJS_TOKEN_DIGIT, NJS_TOKEN_LETTER, -#define NJS_TOKEN_FIRST_CONST NJS_TOKEN_UNDEFINED +#define NJS_TOKEN_FIRST_CONST NJS_TOKEN_NULL - NJS_TOKEN_UNDEFINED, NJS_TOKEN_NULL, NJS_TOKEN_NUMBER, NJS_TOKEN_BOOLEAN, diff -r c86310ffb38a -r f01ee3828b15 src/njs_lexer_keyword.c --- a/src/njs_lexer_keyword.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_lexer_keyword.c Mon Oct 21 15:10:34 2019 +0300 @@ -12,12 +12,9 @@ static const njs_keyword_t njs_keywords /* Values. */ - { njs_str("undefined"), NJS_TOKEN_UNDEFINED, 0 }, { njs_str("null"), NJS_TOKEN_NULL, 0 }, { njs_str("false"), NJS_TOKEN_BOOLEAN, 0 }, { njs_str("true"), NJS_TOKEN_BOOLEAN, 1 }, - { njs_str("NaN"), NJS_TOKEN_NUMBER, NAN }, - { njs_str("Infinity"), NJS_TOKEN_NUMBER, INFINITY }, /* Operators. */ @@ -79,6 +76,7 @@ static const njs_keyword_t njs_keywords { njs_str("MemoryError"), NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, 0 }, /* Module. */ + { njs_str("import"), NJS_TOKEN_IMPORT, 0 }, { njs_str("export"), NJS_TOKEN_EXPORT, 0 }, diff -r c86310ffb38a -r f01ee3828b15 src/njs_parser_expression.c --- a/src/njs_parser_expression.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_parser_expression.c Mon Oct 21 15:10:34 2019 +0300 @@ -617,7 +617,6 @@ njs_parser_unary_expression(njs_vm_t *vm return next; case NJS_TOKEN_NAME: - case NJS_TOKEN_UNDEFINED: njs_parser_syntax_error(vm, parser, "Delete of an unqualified identifier"); diff -r c86310ffb38a -r f01ee3828b15 src/njs_parser_terminal.c --- a/src/njs_parser_terminal.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/njs_parser_terminal.c Mon Oct 21 15:10:34 2019 +0300 @@ -224,12 +224,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p node->u.value = njs_value_null; break; - case NJS_TOKEN_UNDEFINED: - njs_thread_log_debug("JS: undefined"); - - njs_set_undefined(&node->u.value); - break; - case NJS_TOKEN_THIS: njs_thread_log_debug("JS: this"); diff -r c86310ffb38a -r f01ee3828b15 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Oct 18 16:38:55 2019 +0300 +++ b/src/test/njs_unit_test.c Mon Oct 21 15:10:34 2019 +0300 @@ -108,9 +108,6 @@ static njs_unit_test_t njs_test[] = #if 0 /* TODO */ { njs_str("var a; Object.getOwnPropertyDescriptor(this, 'a').value"), njs_str("undefined") }, - - { njs_str("this.a = 1; a"), - njs_str("1") }, #endif { njs_str("f() = 1"), @@ -766,6 +763,9 @@ static njs_unit_test_t njs_test[] = { njs_str("undefined + undefined"), njs_str("NaN") }, + { njs_str("var undefined"), + njs_str("undefined") }, + { njs_str("1.2 + 5.7"), njs_str("6.9") }, @@ -1705,6 +1705,20 @@ static njs_unit_test_t njs_test[] = { njs_str("-Infinity >= Infinity"), njs_str("false") }, + { njs_str("Boolean(Infinity)"), + njs_str("true") }, + + { njs_str("!Infinity === false"), + njs_str("true") }, + + { njs_str("var Infinity"), + njs_str("undefined") }, + +#if 0 /* ES5FIX */ + { njs_str("Infinity = 1"), + njs_str("TypeError: Cannot assign to read-only property "Infinity" of object") }, +#endif + /**/ { njs_str("NaN === NaN"), @@ -1731,6 +1745,14 @@ static njs_unit_test_t njs_test[] = { njs_str("NaN <= NaN"), njs_str("false") }, + { njs_str("var NaN"), + njs_str("undefined") }, + +#if 0 /* ES5FIX */ + { njs_str("NaN = 1"), + njs_str("TypeError: Cannot assign to read-only property "NaN" of object") }, +#endif + /**/ { njs_str("null < 0"), @@ -3215,8 +3237,10 @@ static njs_unit_test_t njs_test[] = { njs_str("null = 1"), njs_str("ReferenceError: Invalid left-hand side in assignment in 1") }, +#if 0 /* ES5FIX */ { njs_str("undefined = 1"), - njs_str("ReferenceError: Invalid left-hand side in assignment in 1") }, + njs_str("TypeError: Cannot assign to read-only property "undefined" of object") }, +#endif { njs_str("null++"), njs_str("ReferenceError: Invalid left-hand side in postfix operation in 1") }, @@ -3462,15 +3486,11 @@ static njs_unit_test_t njs_test[] = { njs_str("var o = { [new Number(12345)]: 1000 }; o[12345]"), njs_str("1000") }, - /* ES5FIX: "SyntaxError". */ - { njs_str("delete NaN"), - njs_str("true") }, - - /* ES5FIX: "SyntaxError". */ + njs_str("SyntaxError: Delete of an unqualified identifier in 1") }, { njs_str("delete Infinity"), - njs_str("true") }, + njs_str("SyntaxError: Delete of an unqualified identifier in 1") }, { njs_str("delete -Infinity"), njs_str("true") }, @@ -7255,6 +7275,12 @@ static njs_unit_test_t njs_test[] = { njs_str("[0].some(function(){return Array.call.bind(isNaN)}())"), njs_str("false") }, + { njs_str("(function (undefined, NaN, Infinity){ return undefined + NaN + Infinity})('x', 'y', 'z')"), + njs_str("xyz") }, + + { njs_str("function f(undefined,NaN, Infinity){ return undefined + NaN + Infinity}; f('x', 'y', 'z')"), + njs_str("xyz") }, + /* Recursive factorial. */ { njs_str("function f(a) {" @@ -9335,6 +9361,14 @@ static njs_unit_test_t njs_test[] = { njs_str("this.a = ()=>1; a()"), njs_str("1") }, + { njs_str("var global = this;" + "function isImmutableConstant(v) {" + " var d = Object.getOwnPropertyDescriptor(global, v);" + " return !d.writable && !d.enumerable && !d.configurable;" + "};" + "['undefined', 'NaN', 'Infinity'].every((v)=>isImmutableConstant(v))"), + njs_str("true") }, + { njs_str("this.undefined = 42"), njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") }, From alexander.borisov at nginx.com Mon Oct 21 13:44:07 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 21 Oct 2019 13:44:07 +0000 Subject: [njs] Improved functions for converting value to number. Message-ID: details: https://hg.nginx.org/njs/rev/55f49a991f4f branches: changeset: 1191:55f49a991f4f user: Alexander Borisov date: Mon Oct 21 16:43:45 2019 +0300 description: Improved functions for converting value to number. Added functions: njs_value_to_number(), njs_value_to_integer(), njs_value_to_length() njs_value_to_int32(), njs_value_to_uint32(), njs_value_to_uint16(). Removed functions: njs_primitive_value_to_number(), njs_primitive_value_to_integer(), njs_primitive_value_to_int32(), njs_primitive_value_to_uint32(), njs_primitive_value_to_length(). Changed return type for njs_number_to_integer() function from int32_t to int64_t. diffstat: src/njs_array.c | 101 +++++++++++++++++++++++----------------------- src/njs_builtin.c | 9 +++- src/njs_number.c | 34 +++++++++++---- src/njs_number.h | 55 ++++++------------------- src/njs_object.c | 11 +---- src/njs_string.c | 37 ++++++++++++----- src/njs_value.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/njs_vmcode.c | 16 +++--- 8 files changed, 238 insertions(+), 140 deletions(-) diffs (691 lines): diff -r f01ee3828b15 -r 55f49a991f4f src/njs_array.c --- a/src/njs_array.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_array.c Mon Oct 21 16:43:45 2019 +0300 @@ -332,14 +332,13 @@ static njs_int_t njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - double num; - int64_t size; - uint32_t length; - njs_int_t ret; - njs_value_t *val; - njs_array_t *array; - njs_object_t *proto; - njs_value_t val_length; + double num; + int64_t size; + uint32_t length; + njs_int_t ret; + njs_value_t *val; + njs_array_t *array; + njs_object_t *proto; proto = njs_object(value); @@ -369,18 +368,16 @@ njs_array_length(njs_vm_t *vm, njs_value } if (njs_slow_path(!njs_is_number(setval))) { - ret = njs_value_to_numeric(vm, &val_length, setval); - if (ret != NJS_OK) { + ret = njs_value_to_number(vm, setval, &num); + if (njs_slow_path(ret != NJS_OK)) { return ret; } - num = njs_number(&val_length); - } else { num = njs_number(setval); } - length = njs_number_to_uint32(num); + length = njs_number_to_length(num); if ((double) length != num) { njs_range_error(vm, "Invalid array length"); @@ -422,28 +419,22 @@ static njs_int_t njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int64_t start, end, length; - njs_int_t ret; - njs_value_t prop_length; - - static const njs_value_t string_length = njs_string("length"); - - ret = njs_value_property(vm, &args[0], njs_value_arg(&string_length), - &prop_length); + int64_t start, end, length; + uint32_t object_length; + njs_int_t ret; + + ret = njs_object_length(vm, njs_arg(args, nargs, 0), &object_length); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } - if (njs_slow_path(!njs_is_primitive(&prop_length))) { - ret = njs_value_to_numeric(vm, &prop_length, &prop_length); - if (ret != NJS_OK) { - return ret; - } + length = object_length; + + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); - length = njs_primitive_value_to_length(&prop_length); - if (start < 0) { start += length; @@ -458,7 +449,10 @@ njs_array_prototype_slice(njs_vm_t *vm, } else { if (njs_is_defined(njs_arg(args, nargs, 2))) { - end = njs_primitive_value_to_integer(njs_argument(args, 2)); + ret = njs_value_to_integer(vm, njs_argument(args, 2), &end); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } } else { end = length; @@ -1724,7 +1718,10 @@ njs_array_prototype_index_of(njs_vm_t *v return ret; } - from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } if (length == 0 || from >= (int64_t) length) { goto not_found; @@ -1781,7 +1778,10 @@ njs_array_prototype_last_index_of(njs_vm } if (nargs > 2) { - from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } } else { from = length - 1; @@ -1868,7 +1868,10 @@ njs_array_prototype_includes(njs_vm_t *v goto not_found; } - from = njs_primitive_value_to_integer(njs_arg(args, nargs, 2)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } if (from < 0) { from += length; @@ -1906,14 +1909,13 @@ static njs_int_t njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_int_t ret; - njs_int_t i, start, end, length; + int64_t start, end; + uint32_t length; + njs_int_t i, ret; njs_array_t *array; - njs_value_t name, prop_length, *this, *value; + njs_value_t name, *this, *value; njs_object_t *object; - static const njs_value_t string_length = njs_string("length"); - this = njs_arg(args, nargs, 0); if (njs_is_primitive(this)) { @@ -1940,30 +1942,27 @@ njs_array_prototype_fill(njs_vm_t *vm, n length = array->length; } else { - ret = njs_value_property(vm, this, njs_value_arg(&string_length), - &prop_length); + ret = njs_object_length(vm, this, &length); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } - - if (njs_slow_path(!njs_is_primitive(&prop_length))) { - ret = njs_value_to_numeric(vm, &prop_length, &prop_length); - if (ret != NJS_OK) { - return ret; - } - } - - length = njs_primitive_value_to_length(&prop_length); } - start = njs_primitive_value_to_integer(njs_arg(args, nargs, 2)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &start); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length); if (njs_is_undefined(njs_arg(args, nargs, 3))) { end = length; } else { - end = njs_primitive_value_to_integer(njs_arg(args, nargs, 3)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 3), &end); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } } end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length); diff -r f01ee3828b15 -r 55f49a991f4f src/njs_builtin.c --- a/src/njs_builtin.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_builtin.c Mon Oct 21 16:43:45 2019 +0300 @@ -992,14 +992,19 @@ static njs_int_t njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + uint32_t n; + njs_int_t ret; njs_str_t str; - njs_uint_t n; njs_value_t *value, *indent; value = njs_arg(args, nargs, 1); indent = njs_arg(args, nargs, 2); - n = njs_primitive_value_to_integer(indent); + ret = njs_value_to_uint32(vm, indent, &n); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + n = njs_min(n, 5); if (njs_vm_value_dump(vm, &str, value, 1, n) != NJS_OK) { diff -r f01ee3828b15 -r 55f49a991f4f src/njs_number.c --- a/src/njs_number.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_number.c Mon Oct 21 16:43:45 2019 +0300 @@ -547,10 +547,10 @@ njs_number_prototype_to_fixed(njs_vm_t * njs_uint_t nargs, njs_index_t unused) { u_char *p; - int32_t frac; + int64_t frac; double number; size_t length, size; - njs_int_t point, prefix, postfix; + njs_int_t ret, point, prefix, postfix; njs_value_t *value; u_char buf[128], buf2[128]; @@ -569,7 +569,11 @@ njs_number_prototype_to_fixed(njs_vm_t * } } - frac = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &frac); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + if (njs_slow_path(frac < 0 || frac > 100)) { njs_range_error(vm, "digits argument must be between 0 and 100"); return NJS_ERROR; @@ -582,7 +586,7 @@ njs_number_prototype_to_fixed(njs_vm_t * } point = 0; - length = njs_fixed_dtoa(number, frac, (char *) buf, &point); + length = njs_fixed_dtoa(number, (njs_int_t) frac, (char *) buf, &point); prefix = 0; postfix = 0; @@ -643,7 +647,8 @@ njs_number_prototype_to_precision(njs_vm { double number; size_t size; - int32_t precision; + int64_t precision; + njs_int_t ret; njs_value_t *value; u_char buf[128]; @@ -672,13 +677,17 @@ njs_number_prototype_to_precision(njs_vm return njs_number_to_string(vm, &vm->retval, value); } - precision = njs_primitive_value_to_integer(njs_argument(args, 1)); + ret = njs_value_to_integer(vm, njs_argument(args, 1), &precision); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + if (njs_slow_path(precision < 1 || precision > 100)) { njs_range_error(vm, "precision argument must be between 1 and 100"); return NJS_ERROR; } - size = njs_dtoa_precision(number, (char *) buf, precision); + size = njs_dtoa_precision(number, (char *) buf, (size_t) precision); return njs_string_new(vm, &vm->retval, buf, size, size); } @@ -690,7 +699,8 @@ njs_number_prototype_to_exponential(njs_ { double number; size_t size; - int32_t frac; + int64_t frac; + njs_int_t ret; njs_value_t *value; u_char buf[128]; @@ -714,7 +724,11 @@ njs_number_prototype_to_exponential(njs_ } if (njs_is_defined(njs_arg(args, nargs, 1))) { - frac = njs_primitive_value_to_integer(njs_argument(args, 1)); + ret = njs_value_to_integer(vm, njs_argument(args, 1), &frac); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + if (njs_slow_path(frac < 0 || frac > 100)) { njs_range_error(vm, "digits argument must be between 0 and 100"); return NJS_ERROR; @@ -724,7 +738,7 @@ njs_number_prototype_to_exponential(njs_ frac = -1; } - size = njs_dtoa_exponential(number, (char *) buf, frac); + size = njs_dtoa_exponential(number, (char *) buf, (njs_int_t) frac); return njs_string_new(vm, &vm->retval, buf, size, size); } diff -r f01ee3828b15 -r 55f49a991f4f src/njs_number.h --- a/src/njs_number.h Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_number.h Mon Oct 21 16:43:45 2019 +0300 @@ -61,10 +61,21 @@ njs_number_to_int64(double num) } -njs_inline int32_t +njs_inline int64_t njs_number_to_integer(double num) { - return (int32_t) njs_number_to_int64(num); + if (njs_slow_path(isinf(num))) { + if (num < 0) { + return INT64_MIN; + } + + return INT64_MAX; + + } else if (njs_slow_path(isnan(num))) { + return 0; + } + + return njs_number_to_int64(num); } @@ -131,46 +142,6 @@ njs_char_to_hex(u_char c) return c; } - -njs_inline double -njs_primitive_value_to_number(const njs_value_t *value) -{ - if (njs_fast_path(njs_is_numeric(value))) { - return njs_number(value); - } - - return njs_string_to_number(value, 0); -} - - -njs_inline int32_t -njs_primitive_value_to_integer(const njs_value_t *value) -{ - return njs_number_to_integer(njs_primitive_value_to_number(value)); -} - - -njs_inline int32_t -njs_primitive_value_to_int32(const njs_value_t *value) -{ - return njs_number_to_int32(njs_primitive_value_to_number(value)); -} - - -njs_inline uint32_t -njs_primitive_value_to_uint32(const njs_value_t *value) -{ - return njs_number_to_uint32(njs_primitive_value_to_number(value)); -} - - -njs_inline uint32_t -njs_primitive_value_to_length(const njs_value_t *value) -{ - return njs_number_to_length(njs_primitive_value_to_number(value)); -} - - njs_inline void njs_uint32_to_string(njs_value_t *value, uint32_t u32) { diff -r f01ee3828b15 -r 55f49a991f4f src/njs_object.c --- a/src/njs_object.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_object.c Mon Oct 21 16:43:45 2019 +0300 @@ -2316,14 +2316,5 @@ njs_object_length(njs_vm_t *vm, njs_valu return ret; } - if (!njs_is_primitive(&value_length)) { - ret = njs_value_to_numeric(vm, &value_length, &value_length); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - } - - *length = njs_primitive_value_to_length(&value_length); - - return NJS_OK; + return njs_value_to_length(vm, &value_length, length); } diff -r f01ee3828b15 -r 55f49a991f4f src/njs_string.c --- a/src/njs_string.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_string.c Mon Oct 21 16:43:45 2019 +0300 @@ -1235,16 +1235,22 @@ static njs_int_t njs_string_prototype_char_at(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - ssize_t start, length; + size_t length; + int64_t start; + njs_int_t ret; njs_slice_prop_t slice; njs_string_prop_t string; slice.string_length = njs_string_prop(&string, &args[0]); - start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + length = 1; - if (start < 0 || start >= (ssize_t) slice.string_length) { + if (start < 0 || start >= (int64_t) slice.string_length) { start = 0; length = 0; } @@ -1395,21 +1401,26 @@ njs_string_prototype_char_code_at(njs_vm njs_uint_t nargs, njs_index_t unused) { double num; - ssize_t index, length; + size_t length; + int64_t index; uint32_t code; + njs_int_t ret; const u_char *start, *end; njs_string_prop_t string; length = njs_string_prop(&string, &args[0]); - index = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); - - if (njs_slow_path(index < 0 || index >= length)) { + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &index); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + if (njs_slow_path(index < 0 || index >= (int64_t) length)) { num = NAN; goto done; } - if ((uint32_t) length == string.size) { + if (length == string.size) { /* Byte or ASCII string. */ code = string.start[index]; @@ -2501,11 +2512,15 @@ njs_string_prototype_repeat(njs_vm_t *vm njs_index_t unused) { u_char *p, *start; - int32_t n, max; - uint32_t size, length; + int64_t n, max; + uint64_t size, length; + njs_int_t ret; njs_string_prop_t string; - n = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &n); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } (void) njs_string_prop(&string, &args[0]); diff -r f01ee3828b15 -r 55f49a991f4f src/njs_value.h --- a/src/njs_value.h Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_value.h Mon Oct 21 16:43:45 2019 +0300 @@ -845,10 +845,12 @@ njs_int_t njs_value_property_delete(njs_ njs_value_t *key, njs_value_t *removed); +#include "njs_number.h" + + njs_inline njs_int_t -njs_value_to_numeric(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value) +njs_value_to_number(njs_vm_t *vm, njs_value_t *value, double *dst) { - double num; njs_int_t ret; njs_value_t primitive; @@ -862,14 +864,30 @@ njs_value_to_numeric(njs_vm_t *vm, njs_v } if (njs_slow_path(!njs_is_numeric(value))) { - num = NAN; + *dst = NAN; if (njs_is_string(value)) { - num = njs_string_to_number(value, 0); + *dst = njs_string_to_number(value, 0); } - } else { - num = njs_number(value); + return NJS_OK; + } + + *dst = njs_number(value); + + return NJS_OK; +} + + +njs_inline njs_int_t +njs_value_to_numeric(njs_vm_t *vm, njs_value_t *value, njs_value_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } njs_set_number(dst, num); @@ -879,6 +897,91 @@ njs_value_to_numeric(njs_vm_t *vm, njs_v njs_inline njs_int_t +njs_value_to_integer(njs_vm_t *vm, njs_value_t *value, int64_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + *dst = njs_number_to_integer(num); + + return NJS_OK; +} + + +njs_inline njs_int_t +njs_value_to_length(njs_vm_t *vm, njs_value_t *value, uint32_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + *dst = njs_number_to_length(num); + + return NJS_OK; +} + + +njs_inline njs_int_t +njs_value_to_int32(njs_vm_t *vm, njs_value_t *value, int32_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + *dst = njs_number_to_int32(num); + + return NJS_OK; +} + + +njs_inline njs_int_t +njs_value_to_uint32(njs_vm_t *vm, njs_value_t *value, uint32_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + *dst = njs_number_to_uint32(num); + + return NJS_OK; +} + + +njs_inline njs_int_t +njs_value_to_uint16(njs_vm_t *vm, njs_value_t *value, uint16_t *dst) +{ + double num; + njs_int_t ret; + + ret = njs_value_to_number(vm, value, &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + *dst = njs_number_to_uint16(num); + + return NJS_OK; +} + + +njs_inline njs_int_t njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value) { njs_int_t ret; diff -r f01ee3828b15 -r 55f49a991f4f src/njs_vmcode.c --- a/src/njs_vmcode.c Mon Oct 21 15:10:34 2019 +0300 +++ b/src/njs_vmcode.c Mon Oct 21 16:43:45 2019 +0300 @@ -183,7 +183,7 @@ next: case NJS_VMCODE_DECREMENT: case NJS_VMCODE_POST_DECREMENT: if (njs_slow_path(!njs_is_numeric(value2))) { - ret = njs_value_to_numeric(vm, &numeric1, value2); + ret = njs_value_to_numeric(vm, value2, &numeric1); if (njs_slow_path(ret != NJS_OK)) { goto error; } @@ -350,8 +350,8 @@ next: case NJS_VMCODE_RIGHT_SHIFT: case NJS_VMCODE_UNSIGNED_RIGHT_SHIFT: if (njs_slow_path(!njs_is_numeric(value1))) { - ret = njs_value_to_numeric(vm, &numeric1, value1); - if (ret != NJS_OK) { + ret = njs_value_to_numeric(vm, value1, &numeric1); + if (njs_slow_path(ret != NJS_OK)) { goto error; } @@ -359,8 +359,8 @@ next: } if (njs_slow_path(!njs_is_numeric(value2))) { - ret = njs_value_to_numeric(vm, &numeric2, value2); - if (ret != NJS_OK) { + ret = njs_value_to_numeric(vm, value2, &numeric2); + if (njs_slow_path(ret != NJS_OK)) { goto error; } @@ -517,8 +517,8 @@ next: case NJS_VMCODE_UNARY_NEGATION: case NJS_VMCODE_BITWISE_NOT: if (njs_slow_path(!njs_is_numeric(value1))) { - ret = njs_value_to_numeric(vm, &numeric1, value1); - if (ret != NJS_OK) { + ret = njs_value_to_numeric(vm, value1, &numeric1); + if (njs_slow_path(ret != NJS_OK)) { goto error; } @@ -538,7 +538,7 @@ next: break; case NJS_VMCODE_BITWISE_NOT: - njs_set_int32(retval, ~njs_number_to_integer(num)); + njs_set_int32(retval, ~njs_number_to_uint32(num)); } pc += sizeof(njs_vmcode_2addr_t); From mdounin at mdounin.ru Mon Oct 21 16:10:28 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 21 Oct 2019 16:10:28 +0000 Subject: [nginx] Win32: improved fallback on FormatMessage() errors. Message-ID: details: https://hg.nginx.org/nginx/rev/746567d633ac branches: changeset: 7585:746567d633ac user: Maxim Dounin date: Mon Oct 21 19:06:12 2019 +0300 description: Win32: improved fallback on FormatMessage() errors. FormatMessage() seems to return many errors which essentially indicate that the language in question is not available. At least the following were observed in the wild and during testing: ERROR_MUI_FILE_NOT_FOUND (15100) (ticket #1868), ERROR_RESOURCE_TYPE_NOT_FOUND (1813). While documentation says it should be ERROR_RESOURCE_LANG_NOT_FOUND (1815), this doesn't seem to be the case. As such, checking error code was removed, and as long as FormatMessage() returns an error, we now always try the default language. diffstat: src/os/win32/ngx_errno.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/src/os/win32/ngx_errno.c b/src/os/win32/ngx_errno.c --- a/src/os/win32/ngx_errno.c +++ b/src/os/win32/ngx_errno.c @@ -22,7 +22,7 @@ ngx_strerror(ngx_err_t err, u_char *errs len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, lang, (char *) errstr, size, NULL); - if (len == 0 && lang && GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND) { + if (len == 0 && lang) { /* * Try to use English messages first and fallback to a language, From mdounin at mdounin.ru Mon Oct 21 16:10:29 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 21 Oct 2019 16:10:29 +0000 Subject: [nginx] Win32: silenced -Wcast-function-type GCC warning (ticket #1865). Message-ID: details: https://hg.nginx.org/nginx/rev/4f6e315eef15 branches: changeset: 7586:4f6e315eef15 user: Maxim Dounin date: Mon Oct 21 19:07:03 2019 +0300 description: Win32: silenced -Wcast-function-type GCC warning (ticket #1865). With MinGW-w64, building 64-bit nginx binary with GCC 8 and above results in warning due to cast of GetProcAddress() result to ngx_wsapoll_pt, which GCC thinks is incorrect. Added intermediate cast to "void *" to silence the warning. diffstat: src/os/win32/ngx_win32_init.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c --- a/src/os/win32/ngx_win32_init.c +++ b/src/os/win32/ngx_win32_init.c @@ -240,7 +240,7 @@ ngx_os_init(ngx_log_t *log) goto nopoll; } - WSAPoll = (ngx_wsapoll_pt) GetProcAddress(hmod, "WSAPoll"); + WSAPoll = (ngx_wsapoll_pt) (void *) GetProcAddress(hmod, "WSAPoll"); if (WSAPoll == NULL) { ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, "GetProcAddress(\"WSAPoll\") failed"); From xeioex at nginx.com Tue Oct 22 11:17:23 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 22 Oct 2019 11:17:23 +0000 Subject: [njs] Added tag 0.3.6 for changeset 7b302775917b Message-ID: details: https://hg.nginx.org/njs/rev/e175a2e74ae8 branches: changeset: 1193:e175a2e74ae8 user: Dmitry Volyntsev date: Tue Oct 22 14:16:59 2019 +0300 description: Added tag 0.3.6 for changeset 7b302775917b diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 7b302775917b -r e175a2e74ae8 .hgtags --- a/.hgtags Tue Oct 22 14:16:46 2019 +0300 +++ b/.hgtags Tue Oct 22 14:16:59 2019 +0300 @@ -29,3 +29,4 @@ 82101d50fff6e4c7a92c0542a3d6026ff7e462fb c65a4be9867d434ca449a18d868305d5dcd5b91b 0.3.3 8eadbb3a7c7b7c3426f73adabfa251cd9d296752 0.3.4 b7fa83f27f1b64443b88c990e1851f59583b2182 0.3.5 +7b302775917b72537e1abdbd5dc9d04e55a7d582 0.3.6 From xeioex at nginx.com Tue Oct 22 11:17:23 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 22 Oct 2019 11:17:23 +0000 Subject: [njs] Version 0.3.6. Message-ID: details: https://hg.nginx.org/njs/rev/7b302775917b branches: changeset: 1192:7b302775917b user: Dmitry Volyntsev date: Tue Oct 22 14:16:46 2019 +0300 description: Version 0.3.6. diffstat: CHANGES | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 73 insertions(+), 0 deletions(-) diffs (97 lines): diff -r 55f49a991f4f -r 7b302775917b CHANGES --- a/CHANGES Mon Oct 21 16:43:45 2019 +0300 +++ b/CHANGES Tue Oct 22 14:16:46 2019 +0300 @@ -1,6 +1,77 @@ + +Changes with njs 0.3.6 22 Oct 2019 + + nginx modules: + + *) Improvement: getting special headers from r.headersIn. + + Core: + + *) Feature: added new Function() support. + + *) Feature: added Number.prototype.toFixed(). + + *) Feature: added Number.prototype.toPrecision(). + + *) Feature: added Number.prototype.toExponential(). + + *) Improvement: making "prototype" property of function + instances writable. + + *) Improvement: limiting recursion depth while compiling. + + *) Improvement: moving global functions to the global object. + + *) Bugfix: fixed prototype mutation for object literals. + + *) Bugfix: fixed heap-buffer-overflow while parsing regexp literals. + + *) Bugfix: fixed integer-overflow while parsing exponent + of number literals. + + *) Bugfix: fixed parseFloat(). + + *) Bugfix: fixed Array.prototype functions according to the specification. + The following functions were fixed: every, includes, indexOf, filter, + find, findIndex, forEach, lastIndexOf, map, pop, push, reduce, + reduceRight, shift, some, unshift. + + *) Bugfix: fixed handing of accessor descriptors in Object.freeze(). + + *) Bugfix: fixed String.prototype.replace() when first argument + is not a string. + + *) Bugfix: fixed stack-use-after-scope in Array.prototype.map(). + + *) Bugfix: Date.prototype.toUTCString() format was aligned to ES9. + + *) Bugfix: fixed buffer overflow in Number.prototype.toString(radix). + + *) Bugfix: fixed Regexp.prototype.test() for regexps with backreferences. + + *) Bugfix: fixed Array.prototype.map() for objects with nonexistent values. + + *) Bugfix: fixed Array.prototype.pop() and shift() for sparse objects. + + *) Bugfix: fixed Date.UTC() according to the specification. + + *) Bugfix: fixed Date() constructor according to the specification. + + *) Bugfix: fixed type of Date.prototype. + Thanks to Artem S. Povalyukhin. + + *) Bugfix: fixed Date.prototype.setTime(). + Thanks to Artem S. Povalyukhin. + + *) Bugfix: fixed default number of arguments expected by built-in functions. + + *) Bugfix: fixed "caller" and "arguments" properties of a function instance. + Thanks to Artem S. Povalyukhin. Changes with njs 0.3.5 15 Aug 2019 + Core: + *) Bugfix: fixed module importing using require(). The bug was introduced in 0.3.4. @@ -9,6 +80,7 @@ Changes with njs 0.3.5 Changes with njs 0.3.4 13 Aug 2019 Core: + *) Feature: added Object shorthand methods and computed property names. Thanks to ??? (Hong Zhi Dao) and Artem S. Povalyukhin. @@ -99,6 +171,7 @@ Changes with njs 0.3.3 *) Bugfix: fixed processing empty output chain in stream body filter. Core: + *) Feature: added runtime support for property getter/setter. Thanks to ??? (Hong Zhi Dao) and Artem S. Povalyukhin. From xeioex at nginx.com Tue Oct 22 12:26:16 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 22 Oct 2019 12:26:16 +0000 Subject: [njs] Version bump. Message-ID: details: https://hg.nginx.org/njs/rev/425cbc7d57b3 branches: changeset: 1194:425cbc7d57b3 user: Dmitry Volyntsev date: Tue Oct 22 14:43:30 2019 +0300 description: Version bump. diffstat: src/njs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r e175a2e74ae8 -r 425cbc7d57b3 src/njs.h --- a/src/njs.h Tue Oct 22 14:16:59 2019 +0300 +++ b/src/njs.h Tue Oct 22 14:43:30 2019 +0300 @@ -11,7 +11,7 @@ #include -#define NJS_VERSION "0.3.6" +#define NJS_VERSION "0.3.7" #include /* STDOUT_FILENO, STDERR_FILENO */ From mdounin at mdounin.ru Tue Oct 22 15:20:48 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 22 Oct 2019 15:20:48 +0000 Subject: [nginx] nginx-1.17.5-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/9af0dddbddb2 branches: changeset: 7587:9af0dddbddb2 user: Maxim Dounin date: Tue Oct 22 18:16:08 2019 +0300 description: nginx-1.17.5-RELEASE diffstat: docs/xml/nginx/changes.xml | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 63 insertions(+), 0 deletions(-) diffs (73 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,69 @@ + + + + +?????? nginx ?????????? ????? ioctl(FIONREAD), ???? ?? ????????, +????? ???????? ?????? ?? ???????? ?????????? ? ??????? ??????? ???????. + + +now nginx uses ioctl(FIONREAD), if available, +to avoid reading from a fast connection for a long time. + + + + + +???????? ?????????????? ??????? ? ????? URI ??????? ??????????????. + + +incomplete escaped characters at the end of the request URI were ignored. + + + + + +"/." ? "/.." ? ????? URI ??????? ?? ?????????????????. + + +"/." and "/.." at the end of the request URI were not normalized. + + + + + +? ????????? merge_slashes. + + +in the "merge_slashes" directive. + + + + + +? ????????? ignore_invalid_headers.
+??????? Alan Kemp. +
+ +in the "ignore_invalid_headers" directive.
+Thanks to Alan Kemp. +
+
+ + + +nginx ?? ????????? ? MinGW-w64 gcc 8.1 ? ?????. + + +nginx could not be built with MinGW-w64 gcc 8.1 or newer. + + + +
+ + From mdounin at mdounin.ru Tue Oct 22 15:20:49 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 22 Oct 2019 15:20:49 +0000 Subject: [nginx] release-1.17.5 tag Message-ID: details: https://hg.nginx.org/nginx/rev/f292a38a93f5 branches: changeset: 7588:f292a38a93f5 user: Maxim Dounin date: Tue Oct 22 18:16:08 2019 +0300 description: release-1.17.5 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -443,3 +443,4 @@ 7816bd7dabf6ee86c53c073b90a7143161546e06 2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2 ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3 ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4 +9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5 From alexander.borisov at nginx.com Tue Oct 22 17:00:03 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 22 Oct 2019 17:00:03 +0000 Subject: [njs] Removed argument prototypes for built-in functions. Message-ID: details: https://hg.nginx.org/njs/rev/47cdd4680fc2 branches: changeset: 1195:47cdd4680fc2 user: Alexander Borisov date: Tue Oct 22 19:58:52 2019 +0300 description: Removed argument prototypes for built-in functions. Many JS functions do not have fixed prototypes as in C. For example String.prototype.replace() accepts RegExp or String as the first argument. diffstat: src/njs_array.c | 123 +++- src/njs_boolean.c | 4 +- src/njs_builtin.c | 89 +-- src/njs_crypto.c | 22 +- src/njs_date.c | 692 +++++++++++++++++++++++++----- src/njs_error.c | 21 +- src/njs_fs.c | 51 +- src/njs_function.c | 162 +------ src/njs_function.h | 11 - src/njs_json.c | 25 +- src/njs_math.c | 790 ++++++++++++++++++++------------- src/njs_module.c | 8 + src/njs_number.c | 253 ++++++---- src/njs_number.h | 2 +- src/njs_object.c | 82 +- src/njs_regexp.c | 39 +- src/njs_string.c | 915 +++++++++++++++++++++++++++++---------- src/njs_value.c | 37 - src/njs_value.h | 7 +- src/test/njs_interactive_test.c | 2 +- src/test/njs_unit_test.c | 18 + 21 files changed, 2161 insertions(+), 1192 deletions(-) diffs (truncated from 6563 to 1000 lines): diff -r 425cbc7d57b3 -r 47cdd4680fc2 src/njs_array.c --- a/src/njs_array.c Tue Oct 22 14:43:30 2019 +0300 +++ b/src/njs_array.c Tue Oct 22 19:58:52 2019 +0300 @@ -304,7 +304,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("isArray"), - .value = njs_native_function(njs_array_is_array, 1, 0), + .value = njs_native_function(njs_array_is_array, 1), .writable = 1, .configurable = 1, }, @@ -314,7 +314,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("of"), - .value = njs_native_function(njs_array_of, 0, 0), + .value = njs_native_function(njs_array_of, 0), .writable = 1, .configurable = 1, }, @@ -423,6 +423,11 @@ njs_array_prototype_slice(njs_vm_t *vm, uint32_t object_length; njs_int_t ret; + if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { + njs_type_error(vm, "cannot convert undefined to object"); + return NJS_ERROR; + } + ret = njs_object_length(vm, njs_arg(args, nargs, 0), &object_length); if (njs_slow_path(ret == NJS_ERROR)) { return ret; @@ -933,11 +938,17 @@ static njs_int_t njs_array_prototype_splice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + int64_t n, start, length, items, delta, delete; njs_int_t ret; - njs_int_t n, start, length, items, delta, delete; njs_uint_t i; + njs_value_t *value; njs_array_t *array, *deleted; + if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { + njs_type_error(vm, "cannot convert undefined to object"); + return NJS_ERROR; + } + array = NULL; start = 0; delete = 0; @@ -947,7 +958,17 @@ njs_array_prototype_splice(njs_vm_t *vm, length = array->length; if (nargs > 1) { - start = njs_number(&args[1]); + value = njs_argument(args, 1); + + if (njs_slow_path(!njs_is_number(value))) { + ret = njs_value_to_integer(vm, value, &start); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + } else { + start = njs_number_to_integer(njs_number(value)); + } if (start < 0) { start += length; @@ -963,7 +984,17 @@ njs_array_prototype_splice(njs_vm_t *vm, delete = length - start; if (nargs > 2) { - n = njs_number(&args[2]); + value = njs_argument(args, 2); + + if (njs_slow_path(!njs_is_number(value))) { + ret = njs_value_to_integer(vm, value, &n); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + } else { + n = njs_number_to_integer(njs_number(value)); + } if (n < 0) { delete = 0; @@ -988,12 +1019,7 @@ njs_array_prototype_splice(njs_vm_t *vm, deleted->start[i] = array->start[n]; } - items = nargs - 3; - - if (items < 0) { - items = 0; - } - + items = (nargs > 3) ? nargs - 3: 0; delta = items - delete; if (delta != 0) { @@ -1037,6 +1063,11 @@ njs_array_prototype_reverse(njs_vm_t *vm njs_value_t value; njs_array_t *array; + if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { + njs_type_error(vm, "cannot convert undefined to object"); + return NJS_ERROR; + } + if (njs_is_array(&args[0])) { array = njs_array(&args[0]); length = array->length; @@ -1100,6 +1131,18 @@ njs_array_prototype_join(njs_vm_t *vm, n njs_value_t *value, *values; njs_string_prop_t separator, string; + if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { + njs_type_error(vm, "cannot convert undefined to object"); + return NJS_ERROR; + } + + if (nargs > 1 && !njs_is_string(&args[1])) { + ret = njs_value_to_string(vm, &args[1], &args[1]); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + if (!njs_is_array(&args[0]) || njs_array_len(&args[0]) == 0) { vm->retval = njs_string_empty; return NJS_OK; @@ -2614,7 +2657,6 @@ njs_array_string_sort(njs_vm_t *vm, njs_ static const njs_function_t njs_array_string_sort_function = { .object = { .type = NJS_FUNCTION, .shared = 1, .extensible = 1 }, .native = 1, - .args_types = { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG }, .args_offset = 1, .u.native = njs_array_string_sort, }; @@ -2735,8 +2777,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("slice"), - .value = njs_native_function(njs_array_prototype_slice, 2, - NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_array_prototype_slice, 2), .writable = 1, .configurable = 1, }, @@ -2744,7 +2785,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("push"), - .value = njs_native_function(njs_array_prototype_push, 1, 0), + .value = njs_native_function(njs_array_prototype_push, 1), .writable = 1, .configurable = 1, }, @@ -2752,7 +2793,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("pop"), - .value = njs_native_function(njs_array_prototype_pop, 0, 0), + .value = njs_native_function(njs_array_prototype_pop, 0), .writable = 1, .configurable = 1, }, @@ -2760,7 +2801,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("unshift"), - .value = njs_native_function(njs_array_prototype_unshift, 1, 0), + .value = njs_native_function(njs_array_prototype_unshift, 1), .writable = 1, .configurable = 1, }, @@ -2768,7 +2809,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("shift"), - .value = njs_native_function(njs_array_prototype_shift, 0, 0), + .value = njs_native_function(njs_array_prototype_shift, 0), .writable = 1, .configurable = 1, }, @@ -2776,8 +2817,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("splice"), - .value = njs_native_function(njs_array_prototype_splice, 2, - NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_array_prototype_splice, 2), .writable = 1, .configurable = 1, }, @@ -2785,8 +2825,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reverse"), - .value = njs_native_function(njs_array_prototype_reverse, 0, - NJS_OBJECT_ARG), + .value = njs_native_function(njs_array_prototype_reverse, 0), .writable = 1, .configurable = 1, }, @@ -2794,7 +2833,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_array_prototype_to_string, 0, 0), + .value = njs_native_function(njs_array_prototype_to_string, 0), .writable = 1, .configurable = 1, }, @@ -2802,8 +2841,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("join"), - .value = njs_native_function(njs_array_prototype_join, 1, - NJS_OBJECT_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_array_prototype_join, 1), .writable = 1, .configurable = 1, }, @@ -2811,7 +2849,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("concat"), - .value = njs_native_function(njs_array_prototype_concat, 1, 0), + .value = njs_native_function(njs_array_prototype_concat, 1), .writable = 1, .configurable = 1, }, @@ -2819,8 +2857,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("indexOf"), - .value = njs_native_function(njs_array_prototype_index_of, 1, - NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_array_prototype_index_of, 1), .writable = 1, .configurable = 1, }, @@ -2828,8 +2865,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("lastIndexOf"), - .value = njs_native_function(njs_array_prototype_last_index_of, 1, - NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_array_prototype_last_index_of, 1), .writable = 1, .configurable = 1, }, @@ -2838,8 +2874,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("includes"), - .value = njs_native_function(njs_array_prototype_includes, 1, - NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_array_prototype_includes, 1), .writable = 1, .configurable = 1, }, @@ -2847,7 +2882,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("forEach"), - .value = njs_native_function(njs_array_prototype_for_each, 1, 0), + .value = njs_native_function(njs_array_prototype_for_each, 1), .writable = 1, .configurable = 1, }, @@ -2855,7 +2890,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("some"), - .value = njs_native_function(njs_array_prototype_some, 1, 0), + .value = njs_native_function(njs_array_prototype_some, 1), .writable = 1, .configurable = 1, }, @@ -2863,7 +2898,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("every"), - .value = njs_native_function(njs_array_prototype_every, 1, 0), + .value = njs_native_function(njs_array_prototype_every, 1), .writable = 1, .configurable = 1, }, @@ -2872,9 +2907,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("fill"), - .value = njs_native_function(njs_array_prototype_fill, 1, - NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG, - NJS_NUMBER_ARG), + .value = njs_native_function(njs_array_prototype_fill, 1), .writable = 1, .configurable = 1, }, @@ -2882,7 +2915,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("filter"), - .value = njs_native_function(njs_array_prototype_filter, 1, 0), + .value = njs_native_function(njs_array_prototype_filter, 1), .writable = 1, .configurable = 1, }, @@ -2891,7 +2924,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("find"), - .value = njs_native_function(njs_array_prototype_find, 1, 0), + .value = njs_native_function(njs_array_prototype_find, 1), .writable = 1, .configurable = 1, }, @@ -2900,7 +2933,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("findIndex"), - .value = njs_native_function(njs_array_prototype_find_index, 1, 0), + .value = njs_native_function(njs_array_prototype_find_index, 1), .writable = 1, .configurable = 1, }, @@ -2908,7 +2941,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("map"), - .value = njs_native_function(njs_array_prototype_map, 1, 0), + .value = njs_native_function(njs_array_prototype_map, 1), .writable = 1, .configurable = 1, }, @@ -2916,7 +2949,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reduce"), - .value = njs_native_function(njs_array_prototype_reduce, 1, 0), + .value = njs_native_function(njs_array_prototype_reduce, 1), .writable = 1, .configurable = 1, }, @@ -2924,7 +2957,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("reduceRight"), - .value = njs_native_function(njs_array_prototype_reduce_right, 1, 0), + .value = njs_native_function(njs_array_prototype_reduce_right, 1), .writable = 1, .configurable = 1, }, @@ -2932,7 +2965,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY, .name = njs_string("sort"), - .value = njs_native_function(njs_array_prototype_sort, 1, 0), + .value = njs_native_function(njs_array_prototype_sort, 1), .writable = 1, .configurable = 1, }, diff -r 425cbc7d57b3 -r 47cdd4680fc2 src/njs_boolean.c --- a/src/njs_boolean.c Tue Oct 22 14:43:30 2019 +0300 +++ b/src/njs_boolean.c Tue Oct 22 19:58:52 2019 +0300 @@ -145,7 +145,7 @@ static const njs_object_prop_t njs_bool { .type = NJS_PROPERTY, .name = njs_string("valueOf"), - .value = njs_native_function(njs_boolean_prototype_value_of, 0, 0), + .value = njs_native_function(njs_boolean_prototype_value_of, 0), .writable = 1, .configurable = 1, }, @@ -153,7 +153,7 @@ static const njs_object_prop_t njs_bool { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_boolean_prototype_to_string, 0, 0), + .value = njs_native_function(njs_boolean_prototype_to_string, 0), .writable = 1, .configurable = 1, }, diff -r 425cbc7d57b3 -r 47cdd4680fc2 src/njs_builtin.c --- a/src/njs_builtin.c Tue Oct 22 14:43:30 2019 +0300 +++ b/src/njs_builtin.c Tue Oct 22 19:58:52 2019 +0300 @@ -11,7 +11,6 @@ typedef struct { njs_function_native_t native; - uint8_t args_types[NJS_ARGS_TYPES_MAX]; } njs_function_init_t; @@ -95,29 +94,25 @@ const njs_object_init_t *njs_constructo const njs_function_init_t njs_native_constructors[] = { /* SunC does not allow empty array initialization. */ - { njs_object_constructor, { 0 } }, - { njs_array_constructor, { 0 } }, - { njs_boolean_constructor, { 0 } }, - { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_function_constructor, { 0 } }, - { njs_regexp_constructor, { 0 } }, - { njs_date_constructor, { 0 } }, - { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, - NJS_STRING_ARG } }, - { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_internal_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_range_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_syntax_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_object_constructor }, + { njs_array_constructor }, + { njs_boolean_constructor }, + { njs_number_constructor }, + { njs_string_constructor }, + { njs_function_constructor}, + { njs_regexp_constructor }, + { njs_date_constructor }, + { njs_hash_constructor }, + { njs_hmac_constructor }, + { njs_error_constructor }, + { njs_eval_error_constructor }, + { njs_internal_error_constructor }, + { njs_range_error_constructor }, + { njs_reference_error_constructor }, + { njs_syntax_error_constructor }, + { njs_type_error_constructor }, + { njs_uri_error_constructor }, + { njs_memory_error_constructor }, }; @@ -331,8 +326,6 @@ njs_builtin_objects_create(njs_vm_t *vm) func->u.native = f->native; - memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); - ret = njs_object_hash_init(vm, &func->object.shared_hash, obj); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; @@ -1038,8 +1031,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("isFinite"), - .value = njs_native_function(njs_number_is_finite, 1, - NJS_SKIP_ARG, NJS_NUMBER_ARG), + .value = njs_native_function(njs_number_global_is_finite, 1), .writable = 1, .configurable = 1, }, @@ -1047,8 +1039,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("isNaN"), - .value = njs_native_function(njs_number_global_is_nan, 1, - NJS_SKIP_ARG, NJS_NUMBER_ARG), + .value = njs_native_function(njs_number_global_is_nan, 1), .writable = 1, .configurable = 1, }, @@ -1056,8 +1047,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("parseFloat"), - .value = njs_native_function(njs_number_parse_float, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_number_parse_float, 1), .writable = 1, .configurable = 1, }, @@ -1065,8 +1055,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("parseInt"), - .value = njs_native_function(njs_number_parse_int, 2, - NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG), + .value = njs_native_function(njs_number_parse_int, 2), .writable = 1, .configurable = 1, }, @@ -1074,7 +1063,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_object_prototype_to_string, 0, 0), + .value = njs_native_function(njs_object_prototype_to_string, 0), .writable = 1, .configurable = 1, }, @@ -1082,8 +1071,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("encodeURI"), - .value = njs_native_function(njs_string_encode_uri, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_string_encode_uri, 1), .writable = 1, .configurable = 1, }, @@ -1091,8 +1079,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_long_string("encodeURIComponent"), - .value = njs_native_function(njs_string_encode_uri_component, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_string_encode_uri_component, 1), .writable = 1, .configurable = 1, }, @@ -1100,8 +1087,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("decodeURI"), - .value = njs_native_function(njs_string_decode_uri, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_string_decode_uri, 1), .writable = 1, .configurable = 1, }, @@ -1109,8 +1095,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_long_string("decodeURIComponent"), - .value = njs_native_function(njs_string_decode_uri_component, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_string_decode_uri_component, 1), .writable = 1, .configurable = 1, }, @@ -1118,7 +1103,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("eval"), - .value = njs_native_function(njs_eval_function, 1, 0), + .value = njs_native_function(njs_eval_function, 1), .writable = 1, .configurable = 1, }, @@ -1126,9 +1111,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("setTimeout"), - .value = njs_native_function(njs_set_timeout, 2, - NJS_SKIP_ARG, NJS_FUNCTION_ARG, - NJS_NUMBER_ARG), + .value = njs_native_function(njs_set_timeout, 2), .writable = 1, .configurable = 1, }, @@ -1136,8 +1119,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("setImmediate"), - .value = njs_native_function(njs_set_immediate, 4, - NJS_SKIP_ARG, NJS_FUNCTION_ARG), + .value = njs_native_function(njs_set_immediate, 4), .writable = 1, .configurable = 1, }, @@ -1145,8 +1127,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("clearTimeout"), - .value = njs_native_function(njs_clear_timeout, 1, - NJS_SKIP_ARG, NJS_NUMBER_ARG), + .value = njs_native_function(njs_clear_timeout, 1), .writable = 1, .configurable = 1, }, @@ -1154,8 +1135,7 @@ static const njs_object_prop_t njs_glob { .type = NJS_PROPERTY, .name = njs_string("require"), - .value = njs_native_function(njs_module_require, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_module_require, 1), .writable = 1, .configurable = 1, }, @@ -1183,8 +1163,7 @@ static const njs_object_prop_t njs_njs_ { .type = NJS_PROPERTY, .name = njs_string("dump"), - .value = njs_native_function(njs_dump_value, 0, - NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG), + .value = njs_native_function(njs_dump_value, 0), .configurable = 1, }, }; diff -r 425cbc7d57b3 -r 47cdd4680fc2 src/njs_crypto.c --- a/src/njs_crypto.c Tue Oct 22 14:43:30 2019 +0300 +++ b/src/njs_crypto.c Tue Oct 22 19:58:52 2019 +0300 @@ -323,7 +323,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_hash_prototype_to_string, 0, 0), + .value = njs_native_function(njs_hash_prototype_to_string, 0), .writable = 1, .configurable = 1, }, @@ -331,8 +331,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("update"), - .value = njs_native_function(njs_hash_prototype_update, 0, - NJS_OBJECT_ARG, NJS_SKIP_ARG), + .value = njs_native_function(njs_hash_prototype_update, 0), .writable = 1, .configurable = 1, }, @@ -340,8 +339,7 @@ static const njs_object_prop_t njs_hash { .type = NJS_PROPERTY, .name = njs_string("digest"), - .value = njs_native_function(njs_hash_prototype_digest, 0, - NJS_OBJECT_ARG, NJS_SKIP_ARG), + .value = njs_native_function(njs_hash_prototype_digest, 0), .writable = 1, .configurable = 1, }, @@ -585,7 +583,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("toString"), - .value = njs_native_function(njs_hmac_prototype_to_string, 0, 0), + .value = njs_native_function(njs_hmac_prototype_to_string, 0), .writable = 1, .configurable = 1, }, @@ -593,8 +591,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("update"), - .value = njs_native_function(njs_hmac_prototype_update, 0, - NJS_OBJECT_ARG, NJS_SKIP_ARG), + .value = njs_native_function(njs_hmac_prototype_update, 0), .writable = 1, .configurable = 1, }, @@ -602,8 +599,7 @@ static const njs_object_prop_t njs_hmac { .type = NJS_PROPERTY, .name = njs_string("digest"), - .value = njs_native_function(njs_hmac_prototype_digest, 0, - NJS_OBJECT_ARG, NJS_SKIP_ARG), + .value = njs_native_function(njs_hmac_prototype_digest, 0), .writable = 1, .configurable = 1, }, @@ -650,8 +646,7 @@ static const njs_object_prop_t njs_cryp { .type = NJS_PROPERTY, .name = njs_string("createHash"), - .value = njs_native_function(njs_crypto_create_hash, 0, - NJS_SKIP_ARG), + .value = njs_native_function(njs_crypto_create_hash, 0), .writable = 1, .configurable = 1, }, @@ -659,8 +654,7 @@ static const njs_object_prop_t njs_cryp { .type = NJS_PROPERTY, .name = njs_string("createHmac"), - .value = njs_native_function(njs_crypto_create_hmac, 0, - NJS_SKIP_ARG), + .value = njs_native_function(njs_crypto_create_hmac, 0), .writable = 1, .configurable = 1, }, diff -r 425cbc7d57b3 -r 47cdd4680fc2 src/njs_date.c --- a/src/njs_date.c Tue Oct 22 14:43:30 2019 +0300 +++ b/src/njs_date.c Tue Oct 22 19:58:52 2019 +0300 @@ -389,9 +389,17 @@ static njs_int_t njs_date_parse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - double time; + double time; + njs_int_t ret; if (nargs > 1) { + if (njs_slow_path(!njs_is_string(&args[1]))) { + ret = njs_value_to_string(vm, &args[1], &args[1]); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + time = njs_date_string_parse(&args[1]); } else { @@ -1016,7 +1024,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("UTC"), - .value = njs_native_function(njs_date_utc, 7, 0), + .value = njs_native_function(njs_date_utc, 7), .writable = 1, .configurable = 1, }, @@ -1024,7 +1032,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("now"), - .value = njs_native_function(njs_date_now, 0, 0), + .value = njs_native_function(njs_date_now, 0), .writable = 1, .configurable = 1, }, @@ -1032,8 +1040,7 @@ static const njs_object_prop_t njs_date { .type = NJS_PROPERTY, .name = njs_string("parse"), - .value = njs_native_function(njs_date_parse, 1, - NJS_SKIP_ARG, NJS_STRING_ARG), + .value = njs_native_function(njs_date_parse, 1), .writable = 1, .configurable = 1, }, @@ -1051,6 +1058,13 @@ static njs_int_t njs_date_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + njs_set_number(&vm->retval, njs_date(&args[0])->time); return NJS_OK; @@ -1061,6 +1075,13 @@ static njs_int_t njs_date_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + return njs_date_string(vm, "%a %b %d %Y %T GMT%z (%Z)", njs_date(&args[0])->time); } @@ -1070,6 +1091,13 @@ static njs_int_t njs_date_prototype_to_date_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + return njs_date_string(vm, "%a %b %d %Y", njs_date(&args[0])->time); } @@ -1078,6 +1106,13 @@ static njs_int_t njs_date_prototype_to_time_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + return njs_date_string(vm, "%T GMT%z (%Z)", njs_date(&args[0])->time); } @@ -1120,6 +1155,13 @@ njs_date_prototype_to_utc_string(njs_vm_ static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + time = njs_date(&args[0])->time; if (!isnan(time)) { @@ -1144,6 +1186,13 @@ static njs_int_t njs_date_prototype_to_iso_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + return njs_date_to_string(vm, &vm->retval, &args[0]); } @@ -1189,6 +1238,13 @@ njs_date_prototype_get_full_year(njs_vm_ time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1212,6 +1268,13 @@ njs_date_prototype_get_utc_full_year(njs time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1235,6 +1298,13 @@ njs_date_prototype_get_month(njs_vm_t *v time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1258,6 +1328,13 @@ njs_date_prototype_get_utc_month(njs_vm_ time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1282,6 +1359,13 @@ njs_date_prototype_get_date(njs_vm_t *vm time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1305,6 +1389,13 @@ njs_date_prototype_get_utc_date(njs_vm_t time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1328,6 +1419,13 @@ njs_date_prototype_get_day(njs_vm_t *vm, time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1351,6 +1449,13 @@ njs_date_prototype_get_utc_day(njs_vm_t time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1374,6 +1479,13 @@ njs_date_prototype_get_hours(njs_vm_t *v time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1398,6 +1510,13 @@ njs_date_prototype_get_utc_hours(njs_vm_ time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1421,6 +1540,13 @@ njs_date_prototype_get_minutes(njs_vm_t time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1445,6 +1571,13 @@ njs_date_prototype_get_utc_minutes(njs_v time_t clock; struct tm tm; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } + value = njs_date(&args[0])->time; if (njs_fast_path(!isnan(value))) { @@ -1466,6 +1599,13 @@ njs_date_prototype_get_seconds(njs_vm_t { double value; + if (njs_slow_path(!njs_is_date(&args[0]))) { + njs_type_error(vm, "cannot convert %s to date", + njs_type_string(args[0].type)); + + return NJS_ERROR; + } From xeioex at nginx.com Wed Oct 23 11:47:15 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 23 Oct 2019 11:47:15 +0000 Subject: [njs] Added njs_vm_array_alloc() and njs_vm_array_push() public API. Message-ID: details: https://hg.nginx.org/njs/rev/5e136f9a5954 branches: changeset: 1196:5e136f9a5954 user: Dmitry Volyntsev date: Wed Oct 23 14:42:38 2019 +0300 description: Added njs_vm_array_alloc() and njs_vm_array_push() public API. diffstat: src/njs.h | 4 ++++ src/njs_vm.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 0 deletions(-) diffs (63 lines): diff -r 47cdd4680fc2 -r 5e136f9a5954 src/njs.h --- a/src/njs.h Tue Oct 22 19:58:52 2019 +0300 +++ b/src/njs.h Wed Oct 23 14:42:38 2019 +0300 @@ -305,6 +305,10 @@ NJS_EXPORT njs_int_t njs_vm_object_alloc NJS_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, const njs_value_t *value, const njs_str_t *key); +NJS_EXPORT njs_int_t njs_vm_array_alloc(njs_vm_t *vm, njs_value_t *retval, + uint32_t spare); +NJS_EXPORT njs_value_t *njs_vm_array_push(njs_vm_t *vm, njs_value_t *value); + NJS_EXPORT njs_int_t njs_vm_json_parse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs); NJS_EXPORT njs_int_t njs_vm_json_stringify(njs_vm_t *vm, njs_value_t *args, diff -r 47cdd4680fc2 -r 5e136f9a5954 src/njs_vm.c --- a/src/njs_vm.c Tue Oct 22 19:58:52 2019 +0300 +++ b/src/njs_vm.c Wed Oct 23 14:42:38 2019 +0300 @@ -938,6 +938,45 @@ done: } +njs_int_t +njs_vm_array_alloc(njs_vm_t *vm, njs_value_t *retval, uint32_t spare) +{ + njs_array_t *array; + + array = njs_array_alloc(vm, 0, spare); + + if (njs_slow_path(array == NULL)) { + return NJS_ERROR; + } + + njs_set_array(retval, array); + + return NJS_OK; +} + + +njs_value_t * +njs_vm_array_push(njs_vm_t *vm, njs_value_t *value) +{ + njs_int_t ret; + njs_array_t *array; + + if (njs_slow_path(!njs_is_array(value))) { + njs_type_error(vm, "njs_vm_array_push() argument is not array"); + return NULL; + } + + array = njs_array(value); + + ret = njs_array_expand(vm, array, 0, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + return &array->start[array->length++]; +} + + njs_value_t * njs_vm_object_prop(njs_vm_t *vm, const njs_value_t *value, const njs_str_t *key) { From xeioex at nginx.com Wed Oct 23 11:47:15 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 23 Oct 2019 11:47:15 +0000 Subject: [njs] Refactoring iteration over external objects. Message-ID: details: https://hg.nginx.org/njs/rev/9e327cd3a33e branches: changeset: 1197:9e327cd3a33e user: Dmitry Volyntsev date: Wed Oct 23 14:42:38 2019 +0300 description: Refactoring iteration over external objects. Previously, two callbacks were required to support array-like iteration for external objects (foreach, next). Instead using only one callback (keys) to simplify. diffstat: nginx/ngx_http_js_module.c | 242 ++++++++++++++++++------------------------ nginx/ngx_stream_js_module.c | 13 -- src/njs.h | 8 +- src/njs_extern.c | 3 +- src/njs_extern.h | 3 +- src/njs_json.c | 8 +- src/njs_shell.c | 6 - src/njs_value.c | 42 +++++++ src/njs_vmcode.c | 94 +--------------- src/test/njs_unit_test.c | 61 ++++------ 10 files changed, 187 insertions(+), 293 deletions(-) diffs (truncated from 1094 to 1000 lines): diff -r 5e136f9a5954 -r 9e327cd3a33e nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Wed Oct 23 14:42:38 2019 +0300 +++ b/nginx/ngx_http_js_module.c Wed Oct 23 14:42:38 2019 +0300 @@ -36,12 +36,6 @@ typedef struct { typedef struct { - ngx_list_part_t *part; - ngx_uint_t item; -} ngx_http_js_table_entry_t; - - -typedef struct { ngx_http_request_t *request; njs_vm_event_t vm_event; void *unused; @@ -62,10 +56,8 @@ static void ngx_http_js_cleanup_vm(void static njs_int_t ngx_http_js_ext_get_string(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); -static njs_int_t ngx_http_js_ext_foreach_header(njs_vm_t *vm, void *obj, - void *next, uintptr_t data); -static njs_int_t ngx_http_js_ext_next_header(njs_vm_t *vm, njs_value_t *value, - void *obj, void *next); +static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj, + njs_value_t *keys, uintptr_t data); static ngx_table_elt_t *ngx_http_js_get_header(ngx_list_part_t *part, u_char *data, size_t len); static njs_int_t ngx_http_js_ext_get_header_out(njs_vm_t *vm, @@ -74,8 +66,8 @@ static njs_int_t ngx_http_js_ext_set_hea uintptr_t data, njs_str_t *value); static njs_int_t ngx_http_js_ext_delete_header_out(njs_vm_t *vm, void *obj, uintptr_t data, njs_bool_t delete); -static njs_int_t ngx_http_js_ext_foreach_header_out(njs_vm_t *vm, void *obj, - void *next); /*FIXME*/ +static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj, + njs_value_t *keys); /*FIXME*/ static njs_int_t ngx_http_js_ext_get_status(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); static njs_int_t ngx_http_js_ext_set_status(njs_vm_t *vm, void *obj, @@ -108,14 +100,12 @@ static njs_int_t ngx_http_js_ext_get_req njs_value_t *value, void *obj, uintptr_t data); static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); -static njs_int_t ngx_http_js_ext_foreach_header_in(njs_vm_t *vm, void *obj, - void *next); /*FIXME*/ +static njs_int_t ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj, + njs_value_t *keys); /*FIXME*/ static njs_int_t ngx_http_js_ext_get_arg(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); -static njs_int_t ngx_http_js_ext_foreach_arg(njs_vm_t *vm, void *obj, - void *next); -static njs_int_t ngx_http_js_ext_next_arg(njs_vm_t *vm, njs_value_t *value, - void *obj, void *next); +static njs_int_t ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj, + njs_value_t *keys); static njs_int_t ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); static njs_int_t ngx_http_js_ext_set_variable(njs_vm_t *vm, void *obj, @@ -229,7 +219,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, offsetof(ngx_http_request_t, uri) }, { njs_str("method"), @@ -241,7 +230,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, offsetof(ngx_http_request_t, method_name) }, { njs_str("httpVersion"), @@ -253,7 +241,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("remoteAddress"), @@ -265,7 +252,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("parent"), @@ -277,7 +263,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("requestBody"), @@ -289,7 +274,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("responseBody"), @@ -301,7 +285,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("headersIn"), @@ -311,8 +294,7 @@ static njs_external_t ngx_http_js_ext_r ngx_http_js_ext_get_header_in, NULL, NULL, - ngx_http_js_ext_foreach_header_in, - ngx_http_js_ext_next_header, + ngx_http_js_ext_keys_header_in, NULL, 0 }, @@ -323,8 +305,7 @@ static njs_external_t ngx_http_js_ext_r ngx_http_js_ext_get_arg, NULL, NULL, - ngx_http_js_ext_foreach_arg, - ngx_http_js_ext_next_arg, + ngx_http_js_ext_keys_arg, NULL, 0 }, @@ -337,7 +318,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, 0 }, { njs_str("status"), @@ -349,7 +329,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, offsetof(ngx_http_request_t, headers_out.status) }, { njs_str("headersOut"), @@ -359,8 +338,7 @@ static njs_external_t ngx_http_js_ext_r ngx_http_js_ext_get_header_out, ngx_http_js_ext_set_header_out, ngx_http_js_ext_delete_header_out, - ngx_http_js_ext_foreach_header_out, - ngx_http_js_ext_next_header, + ngx_http_js_ext_keys_header_out, NULL, 0 }, @@ -372,7 +350,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_subrequest, 0 }, @@ -384,7 +361,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_log, 0 }, @@ -396,7 +372,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_warn, 0 }, @@ -408,7 +383,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_error, 0 }, @@ -420,7 +394,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_send_header, 0 }, @@ -432,7 +405,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_send, 0 }, @@ -444,7 +416,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_finish, 0 }, @@ -456,7 +427,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_return, 0 }, @@ -468,7 +438,6 @@ static njs_external_t ngx_http_js_ext_r NULL, NULL, NULL, - NULL, ngx_http_js_ext_internal_redirect, 0 }, }; @@ -485,7 +454,6 @@ static njs_external_t ngx_http_js_exter NULL, NULL, NULL, - NULL, 0 }, }; @@ -822,64 +790,79 @@ ngx_http_js_ext_get_string(njs_vm_t *vm, static njs_int_t -ngx_http_js_ext_foreach_header(njs_vm_t *vm, void *obj, void *next, +ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj, njs_value_t *keys, uintptr_t data) { char *p = obj; - ngx_list_t *headers; - ngx_http_request_t *r; - ngx_http_js_table_entry_t *entry, **e; - - r = (ngx_http_request_t *) obj; - - entry = ngx_palloc(r->pool, sizeof(ngx_http_js_table_entry_t)); - if (entry == NULL) { + njs_int_t rc, cookie, x_for; + ngx_uint_t item; + ngx_list_t *headers; + njs_value_t *value; + ngx_list_part_t *part; + ngx_table_elt_t *header, *h; + + rc = njs_vm_array_alloc(vm, keys, 8); + if (rc != NJS_OK) { return NJS_ERROR; } headers = (ngx_list_t *) (p + data); - - entry->part = &headers->part; - entry->item = 0; - - e = (ngx_http_js_table_entry_t **) next; - *e = entry; - - return NJS_OK; -} - - -static njs_int_t -ngx_http_js_ext_next_header(njs_vm_t *vm, njs_value_t *value, void *obj, - void *next) -{ - ngx_http_js_table_entry_t **e = next; - - ngx_table_elt_t *header, *h; - ngx_http_js_table_entry_t *entry; - - entry = *e; - - while (entry->part) { - - if (entry->item >= entry->part->nelts) { - entry->part = entry->part->next; - entry->item = 0; + part = &headers->part; + item = 0; + + cookie = 0; + x_for = 0; + + while (part) { + + if (item >= part->nelts) { + part = part->next; + item = 0; continue; } - header = entry->part->elts; - h = &header[entry->item++]; + header = part->elts; + h = &header[item++]; if (h->hash == 0) { continue; } - return njs_vm_value_string_set(vm, value, h->key.data, h->key.len); + if (h->key.len == njs_length("Cookie") + && ngx_strncasecmp(h->key.data, (u_char *) "Cookie", + h->key.len) == 0) + { + if (cookie) { + continue; + } + + cookie = 1; + } + + if (h->key.len == njs_length("X-Forwarded-For") + && ngx_strncasecmp(h->key.data, (u_char *) "X-Forwarded-For", + h->key.len) == 0) + { + if (x_for) { + continue; + } + + x_for = 1; + } + + value = njs_vm_array_push(vm, keys); + if (value == NULL) { + return NJS_ERROR; + } + + rc = njs_vm_value_string_set(vm, value, h->key.data, h->key.len); + if (rc != NJS_OK) { + return NJS_ERROR; + } } - return NJS_DONE; + return NJS_OK; } @@ -1078,9 +1061,9 @@ ngx_http_js_ext_delete_header_out(njs_vm static njs_int_t -ngx_http_js_ext_foreach_header_out(njs_vm_t *vm, void *obj, void *next) +ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj, njs_value_t *keys) { - return ngx_http_js_ext_foreach_header(vm, obj, next, + return ngx_http_js_ext_keys_header(vm, obj, keys, offsetof(ngx_http_request_t, headers_out.headers)); } @@ -1604,9 +1587,9 @@ multi: static njs_int_t -ngx_http_js_ext_foreach_header_in(njs_vm_t *vm, void *obj, void *next) +ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj, njs_value_t *keys) { - return ngx_http_js_ext_foreach_header(vm, obj, next, + return ngx_http_js_ext_keys_header(vm, obj, keys, offsetof(ngx_http_request_t, headers_in.headers)); } @@ -1632,71 +1615,54 @@ ngx_http_js_ext_get_arg(njs_vm_t *vm, nj static njs_int_t -ngx_http_js_ext_foreach_arg(njs_vm_t *vm, void *obj, void *next) +ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj, njs_value_t *keys) { - ngx_str_t *entry, **e; + u_char *v, *p, *start, *end; + njs_int_t rc; + njs_value_t *value; ngx_http_request_t *r; r = (ngx_http_request_t *) obj; - entry = ngx_palloc(r->pool, sizeof(ngx_str_t)); - if (entry == NULL) { + rc = njs_vm_array_alloc(vm, keys, 8); + if (rc != NJS_OK) { return NJS_ERROR; } - *entry = r->args; - - e = (ngx_str_t **) next; - *e = entry; + start = r->args.data; + end = start + r->args.len; + + while (start < end) { + p = ngx_strlchr(start, end, '&'); + if (p == NULL) { + p = end; + } + + v = ngx_strlchr(start, p, '='); + if (v == NULL) { + v = p; + } + + if (v != start) { + value = njs_vm_array_push(vm, keys); + if (value == NULL) { + return NJS_ERROR; + } + + rc = njs_vm_value_string_set(vm, value, start, v - start); + if (rc != NJS_OK) { + return NJS_ERROR; + } + } + + start = p + 1; + } return NJS_OK; } static njs_int_t -ngx_http_js_ext_next_arg(njs_vm_t *vm, njs_value_t *value, void *obj, - void *next) -{ - ngx_str_t **e = next; - - size_t len; - u_char *v, *p, *start, *end; - ngx_str_t *entry; - - entry = *e; - - if (entry->len == 0) { - return NJS_DONE; - } - - start = entry->data; - end = start + entry->len; - - p = ngx_strlchr(start, end, '&'); - if (p == NULL) { - p = end; - } - - v = ngx_strlchr(start, p, '='); - if (v == NULL) { - v = p; - } - - len = v - start; - - if (p != end) { - entry->data = &p[1]; - entry->len = end - entry->data; - - } else { - entry->len = 0; - } - - return njs_vm_value_string_set(vm, value, start, len); -} - - -static njs_int_t ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data) { diff -r 5e136f9a5954 -r 9e327cd3a33e nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Wed Oct 23 14:42:38 2019 +0300 +++ b/nginx/ngx_stream_js_module.c Wed Oct 23 14:42:38 2019 +0300 @@ -211,7 +211,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, 0 }, { njs_str("variables"), @@ -223,7 +222,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, 0 }, { njs_str("allow"), @@ -234,7 +232,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_done, 0 }, @@ -246,7 +243,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_deny, 0 }, @@ -258,7 +254,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_decline, 0 }, @@ -270,7 +265,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_done, 0 }, @@ -282,7 +276,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_log, 0 }, @@ -294,7 +287,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_warn, 0 }, @@ -306,7 +298,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_error, 0 }, @@ -318,7 +309,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_on, 0 }, @@ -330,7 +320,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_off, 0 }, @@ -342,7 +331,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, ngx_stream_js_ext_send, 0 }, @@ -360,7 +348,6 @@ static njs_external_t ngx_stream_js_ext NULL, NULL, NULL, - NULL, 0 }, }; diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs.h --- a/src/njs.h Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs.h Wed Oct 23 14:42:38 2019 +0300 @@ -66,9 +66,8 @@ typedef njs_int_t (*njs_extern_set_t)(nj njs_str_t *value); typedef njs_int_t (*njs_extern_find_t)(njs_vm_t *vm, void *obj, uintptr_t data, njs_bool_t delete); -typedef njs_int_t (*njs_extern_foreach_t)(njs_vm_t *vm, void *obj, void *next); -typedef njs_int_t (*njs_extern_next_t)(njs_vm_t *vm, njs_value_t *value, - void *obj, void *next); +typedef njs_int_t (*njs_extern_keys_t)(njs_vm_t *vm, void *obj, + njs_value_t *keys); typedef njs_int_t (*njs_extern_method_t)(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); @@ -92,8 +91,7 @@ struct njs_external_s { njs_extern_set_t set; njs_extern_find_t find; - njs_extern_foreach_t foreach; - njs_extern_next_t next; + njs_extern_keys_t keys; njs_extern_method_t method; diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_extern.c --- a/src/njs_extern.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_extern.c Wed Oct 23 14:42:38 2019 +0300 @@ -89,8 +89,7 @@ njs_vm_external_add(njs_vm_t *vm, njs_lv ext->get = external->get; ext->set = external->set; ext->find = external->find; - ext->foreach = external->foreach; - ext->next = external->next; + ext->keys = external->keys; ext->data = external->data; if (external->method != NULL) { diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_extern.h --- a/src/njs_extern.h Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_extern.h Wed Oct 23 14:42:38 2019 +0300 @@ -26,8 +26,7 @@ struct njs_extern_s { njs_extern_set_t set; njs_extern_find_t find; - njs_extern_foreach_t foreach; - njs_extern_next_t next; + njs_extern_keys_t keys; njs_function_t *function; diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_json.c --- a/src/njs_json.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_json.c Wed Oct 23 14:42:38 2019 +0300 @@ -2295,12 +2295,8 @@ njs_dump_value(njs_json_stringify_t *str njs_dump_item("\"find\""); } - if (ext_proto->foreach != NULL) { - njs_dump_item("\"foreach\""); - } - - if (ext_proto->next != NULL) { - njs_dump_item("\"next\""); + if (ext_proto->keys != NULL) { + njs_dump_item("\"keys\""); } return njs_json_buf_append(stringify, "]}", 2); diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_shell.c --- a/src/njs_shell.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_shell.c Wed Oct 23 14:42:38 2019 +0300 @@ -112,7 +112,6 @@ static njs_external_t njs_ext_console[] NULL, NULL, NULL, - NULL, njs_ext_console_log, 0 }, @@ -124,7 +123,6 @@ static njs_external_t njs_ext_console[] NULL, NULL, NULL, - NULL, njs_ext_console_dump, 0 }, @@ -136,7 +134,6 @@ static njs_external_t njs_ext_console[] NULL, NULL, NULL, - NULL, njs_ext_console_help, 0 }, @@ -148,7 +145,6 @@ static njs_external_t njs_ext_console[] NULL, NULL, NULL, - NULL, njs_ext_console_time, 0 }, @@ -160,7 +156,6 @@ static njs_external_t njs_ext_console[] NULL, NULL, NULL, - NULL, njs_ext_console_time_end, 0 }, }; @@ -176,7 +171,6 @@ static njs_external_t njs_externals[] = NULL, NULL, NULL, - NULL, 0 }, }; diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_value.c --- a/src/njs_value.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_value.c Wed Oct 23 14:42:38 2019 +0300 @@ -191,13 +191,34 @@ njs_array_t * njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, njs_object_enum_t kind, njs_bool_t all) { + void *obj; + njs_int_t ret; + njs_value_t keys; njs_object_value_t obj_val; + const njs_extern_t *ext_proto; if (njs_is_object(value)) { return njs_object_enumerate(vm, njs_object(value), kind, all); } if (value->type != NJS_STRING) { + if (kind == NJS_ENUM_KEYS && njs_is_external(value)) { + ext_proto = value->external.proto; + + if (ext_proto->keys != NULL) { + obj = njs_extern_object(vm, value); + + ret = ext_proto->keys(vm, obj, &keys); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + return njs_array(&keys); + } + + return njs_extern_keys_array(vm, ext_proto); + } + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); } @@ -212,13 +233,34 @@ njs_array_t * njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value, njs_object_enum_t kind, njs_bool_t all) { + void *obj; + njs_int_t ret; + njs_value_t keys; njs_object_value_t obj_val; + const njs_extern_t *ext_proto; if (njs_is_object(value)) { return njs_object_own_enumerate(vm, njs_object(value), kind, all); } if (value->type != NJS_STRING) { + if (kind == NJS_ENUM_KEYS && njs_is_external(value)) { + ext_proto = value->external.proto; + + if (ext_proto->keys != NULL) { + obj = njs_extern_object(vm, value); + + ret = ext_proto->keys(vm, obj, &keys); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + return njs_array(&keys); + } + + return njs_extern_keys_array(vm, ext_proto); + } + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); } diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_vmcode.c --- a/src/njs_vmcode.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_vmcode.c Wed Oct 23 14:42:38 2019 +0300 @@ -31,8 +31,6 @@ static njs_jump_off_t njs_vmcode_propert njs_value_t *value, njs_value_t *key); static njs_jump_off_t njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object, njs_value_t *invld, u_char *pc); -static njs_jump_off_t njs_vmcode_property_next(njs_vm_t *vm, - njs_value_t *object, njs_value_t *value, u_char *pc); static njs_jump_off_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object, njs_value_t *constructor); static njs_jump_off_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, @@ -771,25 +769,21 @@ next: break; case NJS_VMCODE_PROPERTY_NEXT: - if (!njs_is_external(value1)) { - pnext = (njs_vmcode_prop_next_t *) pc; - retval = njs_vmcode_operand(vm, pnext->retval); + pnext = (njs_vmcode_prop_next_t *) pc; + retval = njs_vmcode_operand(vm, pnext->retval); - next = value2->data.u.next; + next = value2->data.u.next; - if (next->index < next->array->length) { - *retval = next->array->data[next->index++]; + if (next->index < next->array->length) { + *retval = next->array->data[next->index++]; - ret = pnext->offset; - break; - } + ret = pnext->offset; + break; } - ret = njs_vmcode_property_next(vm, value1, value2, pc); - if (njs_slow_path(ret == NJS_ERROR)) { - goto error; - } + njs_mp_free(vm->mem_pool, next); + ret = sizeof(njs_vmcode_prop_next_t); break; case NJS_VMCODE_THIS: @@ -1306,27 +1300,9 @@ static njs_jump_off_t njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object, njs_value_t *invld, u_char *pc) { - void *obj; - njs_jump_off_t ret; - const njs_extern_t *ext_proto; njs_property_next_t *next; njs_vmcode_prop_foreach_t *code; - if (njs_is_external(object)) { - ext_proto = object->external.proto; - - if (ext_proto->foreach != NULL) { - obj = njs_extern_object(vm, object); - - ret = ext_proto->foreach(vm, obj, &vm->retval); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - } - - goto done; - } - next = njs_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t)); if (njs_slow_path(next == NULL)) { njs_memory_error(vm); @@ -1342,8 +1318,6 @@ njs_vmcode_property_foreach(njs_vm_t *vm vm->retval.data.u.next = next; -done: - code = (njs_vmcode_prop_foreach_t *) pc; return code->offset; @@ -1351,56 +1325,6 @@ done: static njs_jump_off_t -njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value, - u_char *pc) -{ - void *obj; - njs_value_t *retval; - njs_jump_off_t ret; - njs_property_next_t *next; - const njs_extern_t *ext_proto; - njs_vmcode_prop_next_t *code; - - code = (njs_vmcode_prop_next_t *) pc; - retval = njs_vmcode_operand(vm, code->retval); - - if (njs_is_external(object)) { - ext_proto = object->external.proto; - - if (ext_proto->next != NULL) { - obj = njs_extern_object(vm, object); - - ret = ext_proto->next(vm, retval, obj, value); - - if (ret == NJS_OK) { - return code->offset; - } - - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - - /* ret == NJS_DONE. */ - } - - return sizeof(njs_vmcode_prop_next_t); - } - - next = value->data.u.next; - - if (next->index < next->array->length) { - *retval = next->array->data[next->index++]; - - return code->offset; - } - - njs_mp_free(vm->mem_pool, next); - - return sizeof(njs_vmcode_prop_next_t); -} - - -static njs_jump_off_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object, njs_value_t *constructor) { diff -r 5e136f9a5954 -r 9e327cd3a33e src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 23 14:42:38 2019 +0300 @@ -14029,7 +14029,7 @@ static njs_unit_test_t njs_test[] = njs_str("{a:{type:\"property\",props:[\"getter\"]},b:{type:\"property\",props:[\"getter\"]}}") }, { njs_str("njs.dump($r.header)"), - njs_str("{type:\"object\",props:[\"getter\",\"foreach\",\"next\"]}") }, + njs_str("{type:\"object\",props:[\"getter\",\"keys\"]}") }, { njs_str("njs.dump(njs) == `{version:'${njs.version}'}`"), njs_str("true") }, @@ -14988,36 +14988,36 @@ njs_unit_test_header_external(njs_vm_t * static njs_int_t -njs_unit_test_header_foreach_external(njs_vm_t *vm, void *obj, void *next) +njs_unit_test_header_keys_external(njs_vm_t *vm, void *obj, njs_value_t *keys) { - u_char *s; - - s = next; - s[0] = '0'; - s[1] = '0'; + njs_int_t rc, i; + njs_value_t *value; + u_char k[2]; + + rc = njs_vm_array_alloc(vm, keys, 4); + if (rc != NJS_OK) { + return NJS_ERROR; + } + + k[0] = '0'; + k[1] = '1'; + + for (i = 0; i < 3; i++) { + value = njs_vm_array_push(vm, keys); + if (value == NULL) { + return NJS_ERROR; + } + + (void) njs_vm_value_string_set(vm, value, k, 2); + + k[1]++; + } return NJS_OK; } static njs_int_t -njs_unit_test_header_next_external(njs_vm_t *vm, njs_value_t *value, void *obj, - void *next) -{ - u_char *s; - - s = next; - s[1]++; - - if (s[1] == '4') { - return NJS_DONE; - } - - return njs_vm_value_string_set(vm, value, s, 2); -} - - From arut at nginx.com Thu Oct 24 10:55:24 2019 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 24 Oct 2019 10:55:24 +0000 Subject: [nginx] Version bump. Message-ID: details: https://hg.nginx.org/nginx/rev/486d2e0b1b6f branches: changeset: 7589:486d2e0b1b6f user: Roman Arutyunyan date: Thu Oct 24 13:47:28 2019 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r f292a38a93f5 -r 486d2e0b1b6f src/core/nginx.h --- a/src/core/nginx.h Tue Oct 22 18:16:08 2019 +0300 +++ b/src/core/nginx.h Thu Oct 24 13:47:28 2019 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1017005 -#define NGINX_VERSION "1.17.5" +#define nginx_version 1017006 +#define NGINX_VERSION "1.17.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From arut at nginx.com Thu Oct 24 10:55:26 2019 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 24 Oct 2019 10:55:26 +0000 Subject: [nginx] Core: moved PROXY protocol fields out of ngx_connection_t. Message-ID: details: https://hg.nginx.org/nginx/rev/06b01840bd42 branches: changeset: 7590:06b01840bd42 user: Roman Arutyunyan date: Mon Oct 21 18:06:19 2019 +0300 description: Core: moved PROXY protocol fields out of ngx_connection_t. Now a new structure ngx_proxy_protocol_t holds these fields. This allows to add more PROXY protocol fields in the future without modifying the connection structure. diffstat: src/core/ngx_connection.h | 3 +- src/core/ngx_core.h | 1 + src/core/ngx_proxy_protocol.c | 57 +++++++++++++++++++----------- src/core/ngx_proxy_protocol.h | 6 +++ src/http/modules/ngx_http_realip_module.c | 7 +-- src/http/ngx_http_variables.c | 23 ++++++++++-- src/stream/ngx_stream_realip_module.c | 8 ++-- src/stream/ngx_stream_variables.c | 23 ++++++++++-- 8 files changed, 89 insertions(+), 39 deletions(-) diffs (328 lines): diff -r 486d2e0b1b6f -r 06b01840bd42 src/core/ngx_connection.h --- a/src/core/ngx_connection.h Thu Oct 24 13:47:28 2019 +0300 +++ b/src/core/ngx_connection.h Mon Oct 21 18:06:19 2019 +0300 @@ -147,8 +147,7 @@ struct ngx_connection_s { socklen_t socklen; ngx_str_t addr_text; - ngx_str_t proxy_protocol_addr; - in_port_t proxy_protocol_port; + ngx_proxy_protocol_t *proxy_protocol; #if (NGX_SSL || NGX_COMPAT) ngx_ssl_connection_t *ssl; diff -r 486d2e0b1b6f -r 06b01840bd42 src/core/ngx_core.h --- a/src/core/ngx_core.h Thu Oct 24 13:47:28 2019 +0300 +++ b/src/core/ngx_core.h Mon Oct 21 18:06:19 2019 +0300 @@ -26,6 +26,7 @@ typedef struct ngx_event_aio_s ngx typedef struct ngx_connection_s ngx_connection_t; typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_ssl_s ngx_ssl_t; +typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t; typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; typedef struct ngx_udp_connection_s ngx_udp_connection_t; diff -r 486d2e0b1b6f -r 06b01840bd42 src/core/ngx_proxy_protocol.c --- a/src/core/ngx_proxy_protocol.c Thu Oct 24 13:47:28 2019 +0300 +++ b/src/core/ngx_proxy_protocol.c Mon Oct 21 18:06:19 2019 +0300 @@ -47,9 +47,10 @@ static u_char *ngx_proxy_protocol_v2_rea u_char * ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) { - size_t len; - u_char ch, *p, *addr, *port; - ngx_int_t n; + size_t len; + u_char ch, *p, *addr, *port; + ngx_int_t n; + ngx_proxy_protocol_t *pp; static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n"; @@ -105,15 +106,20 @@ ngx_proxy_protocol_read(ngx_connection_t } } - len = p - addr - 1; - c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len); - - if (c->proxy_protocol_addr.data == NULL) { + pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t)); + if (pp == NULL) { return NULL; } - ngx_memcpy(c->proxy_protocol_addr.data, addr, len); - c->proxy_protocol_addr.len = len; + len = p - addr - 1; + + pp->src_addr.data = ngx_pnalloc(c->pool, len); + if (pp->src_addr.data == NULL) { + return NULL; + } + + ngx_memcpy(pp->src_addr.data, addr, len); + pp->src_addr.len = len; for ( ;; ) { if (p == last) { @@ -145,11 +151,13 @@ ngx_proxy_protocol_read(ngx_connection_t goto invalid; } - c->proxy_protocol_port = (in_port_t) n; + pp->src_port = (in_port_t) n; ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol address: %V %d", &c->proxy_protocol_addr, - c->proxy_protocol_port); + "PROXY protocol address: %V %d", &pp->src_addr, + pp->src_port); + + c->proxy_protocol = pp; skip: @@ -220,6 +228,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio socklen_t socklen; ngx_uint_t version, command, family, transport; ngx_sockaddr_t sockaddr; + ngx_proxy_protocol_t *pp; ngx_proxy_protocol_header_t *header; ngx_proxy_protocol_inet_addrs_t *in; #if (NGX_HAVE_INET6) @@ -266,6 +275,11 @@ ngx_proxy_protocol_v2_read(ngx_connectio return end; } + pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t)); + if (pp == NULL) { + return NULL; + } + family = header->family_transport >> 4; switch (family) { @@ -282,7 +296,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio sockaddr.sockaddr_in.sin_port = 0; memcpy(&sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); - c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in->src_port); + pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port); socklen = sizeof(struct sockaddr_in); @@ -304,7 +318,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio sockaddr.sockaddr_in6.sin6_port = 0; memcpy(&sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); - c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in6->src_port); + pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port); socklen = sizeof(struct sockaddr_in6); @@ -321,23 +335,24 @@ ngx_proxy_protocol_v2_read(ngx_connectio return end; } - c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); - if (c->proxy_protocol_addr.data == NULL) { + pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); + if (pp->src_addr.data == NULL) { return NULL; } - c->proxy_protocol_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, - c->proxy_protocol_addr.data, - NGX_SOCKADDR_STRLEN, 0); + pp->src_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, + pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0); ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol v2 address: %V %d", &c->proxy_protocol_addr, - c->proxy_protocol_port); + "PROXY protocol v2 address: %V %d", &pp->src_addr, + pp->src_port); if (buf < end) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, "PROXY protocol v2 %z bytes of tlv ignored", end - buf); } + c->proxy_protocol = pp; + return end; } diff -r 486d2e0b1b6f -r 06b01840bd42 src/core/ngx_proxy_protocol.h --- a/src/core/ngx_proxy_protocol.h Thu Oct 24 13:47:28 2019 +0300 +++ b/src/core/ngx_proxy_protocol.h Mon Oct 21 18:06:19 2019 +0300 @@ -16,6 +16,12 @@ #define NGX_PROXY_PROTOCOL_MAX_HEADER 107 +struct ngx_proxy_protocol_s { + ngx_str_t src_addr; + in_port_t src_port; +}; + + u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last); u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, diff -r 486d2e0b1b6f -r 06b01840bd42 src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c Thu Oct 24 13:47:28 2019 +0300 +++ b/src/http/modules/ngx_http_realip_module.c Mon Oct 21 18:06:19 2019 +0300 @@ -180,12 +180,11 @@ ngx_http_realip_handler(ngx_http_request case NGX_HTTP_REALIP_PROXY: - value = &r->connection->proxy_protocol_addr; - - if (value->len == 0) { + if (r->connection->proxy_protocol == NULL) { return NGX_DECLINED; } + value = &r->connection->proxy_protocol->src_addr; xfwd = NULL; break; @@ -238,7 +237,7 @@ found: != NGX_DECLINED) { if (rlcf->type == NGX_HTTP_REALIP_PROXY) { - ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port); + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port); } return ngx_http_realip_set_addr(r, &addr); diff -r 486d2e0b1b6f -r 06b01840bd42 src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c Thu Oct 24 13:47:28 2019 +0300 +++ b/src/http/ngx_http_variables.c Mon Oct 21 18:06:19 2019 +0300 @@ -1293,11 +1293,19 @@ static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - v->len = r->connection->proxy_protocol_addr.len; + ngx_proxy_protocol_t *pp; + + pp = r->connection->proxy_protocol; + if (pp == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->len = pp->src_addr.len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = r->connection->proxy_protocol_addr.data; + v->data = pp->src_addr.data; return NGX_OK; } @@ -1307,7 +1315,14 @@ static ngx_int_t ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; + ngx_uint_t port; + ngx_proxy_protocol_t *pp; + + pp = r->connection->proxy_protocol; + if (pp == NULL) { + v->not_found = 1; + return NGX_OK; + } v->len = 0; v->valid = 1; @@ -1319,7 +1334,7 @@ ngx_http_variable_proxy_protocol_port(ng return NGX_ERROR; } - port = r->connection->proxy_protocol_port; + port = pp->src_port; if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; diff -r 486d2e0b1b6f -r 06b01840bd42 src/stream/ngx_stream_realip_module.c --- a/src/stream/ngx_stream_realip_module.c Thu Oct 24 13:47:28 2019 +0300 +++ b/src/stream/ngx_stream_realip_module.c Mon Oct 21 18:06:19 2019 +0300 @@ -108,7 +108,7 @@ ngx_stream_realip_handler(ngx_stream_ses c = s->connection; - if (c->proxy_protocol_addr.len == 0) { + if (c->proxy_protocol == NULL) { return NGX_DECLINED; } @@ -116,14 +116,14 @@ ngx_stream_realip_handler(ngx_stream_ses return NGX_DECLINED; } - if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol_addr.data, - c->proxy_protocol_addr.len) + if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol->src_addr.data, + c->proxy_protocol->src_addr.len) != NGX_OK) { return NGX_DECLINED; } - ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port); + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port); return ngx_stream_realip_set_addr(s, &addr); } diff -r 486d2e0b1b6f -r 06b01840bd42 src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Thu Oct 24 13:47:28 2019 +0300 +++ b/src/stream/ngx_stream_variables.c Mon Oct 21 18:06:19 2019 +0300 @@ -557,11 +557,19 @@ static ngx_int_t ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { - v->len = s->connection->proxy_protocol_addr.len; + ngx_proxy_protocol_t *pp; + + pp = s->connection->proxy_protocol; + if (pp == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->len = pp->src_addr.len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = s->connection->proxy_protocol_addr.data; + v->data = pp->src_addr.data; return NGX_OK; } @@ -571,7 +579,14 @@ static ngx_int_t ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; + ngx_uint_t port; + ngx_proxy_protocol_t *pp; + + pp = s->connection->proxy_protocol; + if (pp == NULL) { + v->not_found = 1; + return NGX_OK; + } v->len = 0; v->valid = 1; @@ -583,7 +598,7 @@ ngx_stream_variable_proxy_protocol_port( return NGX_ERROR; } - port = s->connection->proxy_protocol_port; + port = pp->src_port; if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; From arut at nginx.com Thu Oct 24 10:55:28 2019 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 24 Oct 2019 10:55:28 +0000 Subject: [nginx] Parsing server PROXY protocol address and port (ticket #1206). Message-ID: details: https://hg.nginx.org/nginx/rev/89adf49fe76a branches: changeset: 7591:89adf49fe76a user: Roman Arutyunyan date: Mon Oct 21 20:22:30 2019 +0300 description: Parsing server PROXY protocol address and port (ticket #1206). New variables $proxy_protocol_server_addr and $proxy_protocol_server_port are added both to HTTP and Stream. diffstat: src/core/ngx_proxy_protocol.c | 206 ++++++++++++++++++++++++------------- src/core/ngx_proxy_protocol.h | 2 + src/http/ngx_http_variables.c | 23 +++- src/stream/ngx_stream_variables.c | 23 +++- 4 files changed, 173 insertions(+), 81 deletions(-) diffs (419 lines): diff -r 06b01840bd42 -r 89adf49fe76a src/core/ngx_proxy_protocol.c --- a/src/core/ngx_proxy_protocol.c Mon Oct 21 18:06:19 2019 +0300 +++ b/src/core/ngx_proxy_protocol.c Mon Oct 21 20:22:30 2019 +0300 @@ -40,6 +40,10 @@ typedef struct { } ngx_proxy_protocol_inet6_addrs_t; +static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, + u_char *last, ngx_str_t *addr); +static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last, + in_port_t *port, u_char sep); static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last); @@ -48,8 +52,7 @@ u_char * ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) { size_t len; - u_char ch, *p, *addr, *port; - ngx_int_t n; + u_char *p; ngx_proxy_protocol_t *pp; static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n"; @@ -84,81 +87,48 @@ ngx_proxy_protocol_read(ngx_connection_t } p += 5; - addr = p; - - for ( ;; ) { - if (p == last) { - goto invalid; - } - - ch = *p++; - - if (ch == ' ') { - break; - } - - if (ch != ':' && ch != '.' - && (ch < 'a' || ch > 'f') - && (ch < 'A' || ch > 'F') - && (ch < '0' || ch > '9')) - { - goto invalid; - } - } pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t)); if (pp == NULL) { return NULL; } - len = p - addr - 1; - - pp->src_addr.data = ngx_pnalloc(c->pool, len); - if (pp->src_addr.data == NULL) { - return NULL; + p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr); + if (p == NULL) { + goto invalid; } - ngx_memcpy(pp->src_addr.data, addr, len); - pp->src_addr.len = len; - - for ( ;; ) { - if (p == last) { - goto invalid; - } - - if (*p++ == ' ') { - break; - } + p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr); + if (p == NULL) { + goto invalid; } - port = p; - - for ( ;; ) { - if (p == last) { - goto invalid; - } - - if (*p++ == ' ') { - break; - } - } - - len = p - port - 1; - - n = ngx_atoi(port, len); - - if (n < 0 || n > 65535) { + p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' '); + if (p == NULL) { goto invalid; } - pp->src_port = (in_port_t) n; + p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR); + if (p == NULL) { + goto invalid; + } - ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol address: %V %d", &pp->src_addr, - pp->src_port); + if (p == last) { + goto invalid; + } + + if (*p++ != LF) { + goto invalid; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol src: %V %d, dst: %V %d", + &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port); c->proxy_protocol = pp; + return p; + skip: for ( /* void */ ; p < last - 1; p++) { @@ -176,6 +146,82 @@ invalid: } +static u_char * +ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last, + ngx_str_t *addr) +{ + size_t len; + u_char ch, *pos; + + pos = p; + + for ( ;; ) { + if (p == last) { + return NULL; + } + + ch = *p++; + + if (ch == ' ') { + break; + } + + if (ch != ':' && ch != '.' + && (ch < 'a' || ch > 'f') + && (ch < 'A' || ch > 'F') + && (ch < '0' || ch > '9')) + { + return NULL; + } + } + + len = p - pos - 1; + + addr->data = ngx_pnalloc(c->pool, len); + if (addr->data == NULL) { + return NULL; + } + + ngx_memcpy(addr->data, pos, len); + addr->len = len; + + return p; +} + + +static u_char * +ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port, + u_char sep) +{ + size_t len; + u_char *pos; + ngx_int_t n; + + pos = p; + + for ( ;; ) { + if (p == last) { + return NULL; + } + + if (*p++ == sep) { + break; + } + } + + len = p - pos - 1; + + n = ngx_atoi(pos, len); + if (n < 0 || n > 65535) { + return NULL; + } + + *port = (in_port_t) n; + + return p; +} + + u_char * ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) { @@ -227,7 +273,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio size_t len; socklen_t socklen; ngx_uint_t version, command, family, transport; - ngx_sockaddr_t sockaddr; + ngx_sockaddr_t src_sockaddr, dst_sockaddr; ngx_proxy_protocol_t *pp; ngx_proxy_protocol_header_t *header; ngx_proxy_protocol_inet_addrs_t *in; @@ -292,11 +338,16 @@ ngx_proxy_protocol_v2_read(ngx_connectio in = (ngx_proxy_protocol_inet_addrs_t *) buf; - sockaddr.sockaddr_in.sin_family = AF_INET; - sockaddr.sockaddr_in.sin_port = 0; - memcpy(&sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); + src_sockaddr.sockaddr_in.sin_family = AF_INET; + src_sockaddr.sockaddr_in.sin_port = 0; + memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); + + dst_sockaddr.sockaddr_in.sin_family = AF_INET; + dst_sockaddr.sockaddr_in.sin_port = 0; + memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4); pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port); + pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port); socklen = sizeof(struct sockaddr_in); @@ -314,11 +365,16 @@ ngx_proxy_protocol_v2_read(ngx_connectio in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf; - sockaddr.sockaddr_in6.sin6_family = AF_INET6; - sockaddr.sockaddr_in6.sin6_port = 0; - memcpy(&sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); + src_sockaddr.sockaddr_in6.sin6_family = AF_INET6; + src_sockaddr.sockaddr_in6.sin6_port = 0; + memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); + + dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6; + dst_sockaddr.sockaddr_in6.sin6_port = 0; + memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16); pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port); + pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port); socklen = sizeof(struct sockaddr_in6); @@ -340,12 +396,20 @@ ngx_proxy_protocol_v2_read(ngx_connectio return NULL; } - pp->src_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, + pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen, pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol v2 address: %V %d", &pp->src_addr, - pp->src_port); + pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); + if (pp->dst_addr.data == NULL) { + return NULL; + } + + pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen, + pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol v2 src: %V %d, dst: %V %d", + &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port); if (buf < end) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, diff -r 06b01840bd42 -r 89adf49fe76a src/core/ngx_proxy_protocol.h --- a/src/core/ngx_proxy_protocol.h Mon Oct 21 18:06:19 2019 +0300 +++ b/src/core/ngx_proxy_protocol.h Mon Oct 21 20:22:30 2019 +0300 @@ -18,7 +18,9 @@ struct ngx_proxy_protocol_s { ngx_str_t src_addr; + ngx_str_t dst_addr; in_port_t src_port; + in_port_t dst_port; }; diff -r 06b01840bd42 -r 89adf49fe76a src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c Mon Oct 21 18:06:19 2019 +0300 +++ b/src/http/ngx_http_variables.c Mon Oct 21 20:22:30 2019 +0300 @@ -199,10 +199,20 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 }, { ngx_string("proxy_protocol_addr"), NULL, - ngx_http_variable_proxy_protocol_addr, 0, 0, 0 }, + ngx_http_variable_proxy_protocol_addr, + offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 }, { ngx_string("proxy_protocol_port"), NULL, - ngx_http_variable_proxy_protocol_port, 0, 0, 0 }, + ngx_http_variable_proxy_protocol_port, + offsetof(ngx_proxy_protocol_t, src_port), 0, 0 }, + + { ngx_string("proxy_protocol_server_addr"), NULL, + ngx_http_variable_proxy_protocol_addr, + offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 }, + + { ngx_string("proxy_protocol_server_port"), NULL, + ngx_http_variable_proxy_protocol_port, + offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 }, @@ -1293,6 +1303,7 @@ static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { + ngx_str_t *addr; ngx_proxy_protocol_t *pp; pp = r->connection->proxy_protocol; @@ -1301,11 +1312,13 @@ ngx_http_variable_proxy_protocol_addr(ng return NGX_OK; } - v->len = pp->src_addr.len; + addr = (ngx_str_t *) ((char *) pp + data); + + v->len = addr->len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = pp->src_addr.data; + v->data = addr->data; return NGX_OK; } @@ -1334,7 +1347,7 @@ ngx_http_variable_proxy_protocol_port(ng return NGX_ERROR; } - port = pp->src_port; + port = *(in_port_t *) ((char *) pp + data); if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; diff -r 06b01840bd42 -r 89adf49fe76a src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Mon Oct 21 18:06:19 2019 +0300 +++ b/src/stream/ngx_stream_variables.c Mon Oct 21 20:22:30 2019 +0300 @@ -64,10 +64,20 @@ static ngx_stream_variable_t ngx_stream ngx_stream_variable_remote_port, 0, 0, 0 }, { ngx_string("proxy_protocol_addr"), NULL, - ngx_stream_variable_proxy_protocol_addr, 0, 0, 0 }, + ngx_stream_variable_proxy_protocol_addr, + offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 }, { ngx_string("proxy_protocol_port"), NULL, - ngx_stream_variable_proxy_protocol_port, 0, 0, 0 }, + ngx_stream_variable_proxy_protocol_port, + offsetof(ngx_proxy_protocol_t, src_port), 0, 0 }, + + { ngx_string("proxy_protocol_server_addr"), NULL, + ngx_stream_variable_proxy_protocol_addr, + offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 }, + + { ngx_string("proxy_protocol_server_port"), NULL, + ngx_stream_variable_proxy_protocol_port, + offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, { ngx_string("server_addr"), NULL, ngx_stream_variable_server_addr, 0, 0, 0 }, @@ -557,6 +567,7 @@ static ngx_int_t ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { + ngx_str_t *addr; ngx_proxy_protocol_t *pp; pp = s->connection->proxy_protocol; @@ -565,11 +576,13 @@ ngx_stream_variable_proxy_protocol_addr( return NGX_OK; } - v->len = pp->src_addr.len; + addr = (ngx_str_t *) ((char *) pp + data); + + v->len = addr->len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = pp->src_addr.data; + v->data = addr->data; return NGX_OK; } @@ -598,7 +611,7 @@ ngx_stream_variable_proxy_protocol_port( return NGX_ERROR; } - port = pp->src_port; + port = *(in_port_t *) ((char *) pp + data); if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; From alexander.borisov at nginx.com Thu Oct 24 13:15:20 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 24 Oct 2019 13:15:20 +0000 Subject: [njs] Fixed heap-buffer-overflow in njs_array_reverse_iterator() function. Message-ID: details: https://hg.nginx.org/njs/rev/b02b79e30d4a branches: changeset: 1198:b02b79e30d4a user: Alexander Borisov date: Thu Oct 24 16:15:01 2019 +0300 description: Fixed heap-buffer-overflow in njs_array_reverse_iterator() function. Affected JS functions in Array.prototype: lastIndexOf, reduceRight. diffstat: src/njs_array.c | 3 ++- src/test/njs_unit_test.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletions(-) diffs (46 lines): diff -r 9e327cd3a33e -r b02b79e30d4a src/njs_array.c --- a/src/njs_array.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/njs_array.c Thu Oct 24 16:15:01 2019 +0300 @@ -1594,7 +1594,8 @@ njs_array_reverse_iterator(njs_vm_t *vm, } else { /* UTF-8 string. */ - p = njs_string_offset(string_prop.start, end, from + 1); + p = njs_string_offset(string_prop.start, end, from); + p = njs_utf8_next(p, end); i = from + 1; diff -r 9e327cd3a33e -r b02b79e30d4a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 23 14:42:38 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 24 16:15:01 2019 +0300 @@ -4407,6 +4407,17 @@ static njs_unit_test_t njs_test[] = "Array.prototype.lastIndexOf.call(o); i"), njs_str("1") }, + { njs_str("[''].lastIndexOf.call('00000000000000000000000000000?00')"), + njs_str("-1") }, + + { njs_str("var o = '????';" + "Array.prototype.lastIndexOf.call(o, '?', 0)"), + njs_str("0") }, + + { njs_str("var o = '????';" + "Array.prototype.lastIndexOf.call(o, '?', 4)"), + njs_str("0") }, + { njs_str("[1,2,3,4].includes()"), njs_str("false") }, @@ -5029,6 +5040,11 @@ static njs_unit_test_t njs_test[] = "catch (e) {i += '; ' + e} i"), njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var m = [];" + "[''].reduceRight.call('00000000000000000000000000000?00', (p, v, i, a) => {m.push(v)});" + "m.join('')"), + njs_str("0?00000000000000000000000000000") }, + { njs_str("var a = ['1','2','3','4','5','6']; a.sort()"), njs_str("1,2,3,4,5,6") }, From xeioex at nginx.com Thu Oct 24 13:24:27 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 24 Oct 2019 13:24:27 +0000 Subject: [njs] Refactoring Error value types. Message-ID: details: https://hg.nginx.org/njs/rev/a908c2ef62ca branches: changeset: 1199:a908c2ef62ca user: Dmitry Volyntsev date: Thu Oct 24 16:17:16 2019 +0300 description: Refactoring Error value types. Eliminating special value types (njs_value_type_t) for error instance objects. According to the spec error instance objects are ordinary objects which have an [[ErrorData]] internal slot. diffstat: src/njs_builtin.c | 16 ++++++++-------- src/njs_error.c | 38 ++++++++++++++++++++------------------ src/njs_error.h | 22 +++++++++++----------- src/njs_fs.c | 4 ++-- src/njs_generator.c | 3 ++- src/njs_json.c | 11 ++--------- src/njs_module.c | 1 + src/njs_object.c | 15 ++++++--------- src/njs_parser.c | 6 +++--- src/njs_parser.h | 9 +++++---- src/njs_value.c | 32 -------------------------------- src/njs_value.h | 29 ++++++++++++++--------------- src/njs_vm.c | 10 +++++++--- src/njs_vm.h | 6 +++--- src/njs_vmcode.c | 10 +--------- src/test/njs_unit_test.c | 12 ++++++++++++ 16 files changed, 97 insertions(+), 127 deletions(-) diffs (663 lines): diff -r b02b79e30d4a -r a908c2ef62ca src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 24 16:17:16 2019 +0300 @@ -152,14 +152,14 @@ const njs_object_prototype_t njs_protot { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), .object = { .type = NJS_OBJECT } } }, - { .object = { .type = NJS_OBJECT_ERROR } }, - { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, - { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, - { .object = { .type = NJS_OBJECT_REF_ERROR } }, - { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, - { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, - { .object = { .type = NJS_OBJECT_URI_ERROR } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_OBJECT } }, }; diff -r b02b79e30d4a -r a908c2ef62ca src/njs_error.c --- a/src/njs_error.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_error.c Thu Oct 24 16:17:16 2019 +0300 @@ -13,7 +13,7 @@ static const njs_value_t njs_error_name void -njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_value_type_t type, +njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, u_char *start, size_t size) { ssize_t length; @@ -36,12 +36,12 @@ njs_error_new(njs_vm_t *vm, njs_value_t return; } - njs_set_type_object(dst, error, type); + njs_set_object(dst, error); } void -njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_value_type_t type, +njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, const char *fmt, ...) { va_list args; @@ -60,7 +60,7 @@ njs_error_fmt_new(njs_vm_t *vm, njs_valu njs_object_t * -njs_error_alloc(njs_vm_t *vm, njs_value_type_t type, const njs_value_t *name, +njs_error_alloc(njs_vm_t *vm, njs_prototype_t type, const njs_value_t *name, const njs_value_t *message) { njs_int_t ret; @@ -75,10 +75,11 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ njs_lvlhsh_init(&error->hash); njs_lvlhsh_init(&error->shared_hash); - error->type = type; + error->type = NJS_OBJECT; error->shared = 0; error->extensible = 1; - error->__proto__ = &vm->prototypes[njs_error_prototype_index(type)].object; + error->error_data = 1; + error->__proto__ = &vm->prototypes[type].object; lhq.replace = 0; lhq.pool = vm->mem_pool; @@ -135,7 +136,7 @@ memory_error: static njs_int_t njs_error_create(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_value_type_t type) + njs_prototype_t type) { njs_int_t ret; njs_value_t *value; @@ -158,7 +159,7 @@ njs_error_create(njs_vm_t *vm, njs_value return NJS_ERROR; } - njs_set_type_object(&vm->retval, error, type); + njs_set_object(&vm->retval, error); return NJS_OK; } @@ -168,7 +169,7 @@ njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_ERROR); } @@ -210,7 +211,7 @@ njs_int_t njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_EVAL_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_EVAL_ERROR); } @@ -252,7 +253,7 @@ njs_int_t njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_INTERNAL_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_INTERNAL_ERROR); } @@ -294,7 +295,7 @@ njs_int_t njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_RANGE_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_RANGE_ERROR); } @@ -336,7 +337,7 @@ njs_int_t njs_reference_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_REF_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_REF_ERROR); } @@ -378,7 +379,7 @@ njs_int_t njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_SYNTAX_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_SYNTAX_ERROR); } @@ -420,7 +421,7 @@ njs_int_t njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_TYPE_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_TYPE_ERROR); } @@ -462,7 +463,7 @@ njs_int_t njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_OBJECT_URI_ERROR); + return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_URI_ERROR); } @@ -512,7 +513,7 @@ njs_memory_error_set(njs_vm_t *vm, njs_v njs_lvlhsh_init(&object->hash); njs_lvlhsh_init(&object->shared_hash); object->__proto__ = &prototypes[NJS_PROTOTYPE_INTERNAL_ERROR].object; - object->type = NJS_OBJECT_INTERNAL_ERROR; + object->type = NJS_OBJECT; object->shared = 1; /* @@ -520,8 +521,9 @@ njs_memory_error_set(njs_vm_t *vm, njs_v * it from ordinary internal errors. */ object->extensible = 0; + object->error_data = 1; - njs_set_type_object(value, object, NJS_OBJECT_INTERNAL_ERROR); + njs_set_object(value, object); } diff -r b02b79e30d4a -r a908c2ef62ca src/njs_error.h --- a/src/njs_error.h Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_error.h Thu Oct 24 16:17:16 2019 +0300 @@ -9,38 +9,38 @@ #define njs_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_ERROR, fmt, ##__VA_ARGS__) + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_ERROR, fmt, ##__VA_ARGS__) #define njs_eval_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_EVAL_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_EVAL_ERROR, fmt, \ ##__VA_ARGS__) #define njs_internal_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_INTERNAL_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_INTERNAL_ERROR, fmt, \ ##__VA_ARGS__) #define njs_range_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_RANGE_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_RANGE_ERROR, fmt, \ ##__VA_ARGS__) #define njs_reference_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_REF_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_REF_ERROR, fmt, \ ##__VA_ARGS__) #define njs_syntax_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_SYNTAX_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_SYNTAX_ERROR, fmt, \ ##__VA_ARGS__) #define njs_type_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_TYPE_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_TYPE_ERROR, fmt, \ ##__VA_ARGS__) #define njs_uri_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_OBJECT_URI_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_URI_ERROR, fmt, \ ##__VA_ARGS__) -void njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_value_type_t type, +void njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, u_char *start, size_t size); void njs_noinline njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, - njs_value_type_t type, const char *fmt, ...); + njs_prototype_t type, const char *fmt, ...); void njs_memory_error(njs_vm_t *vm); void njs_memory_error_set(njs_vm_t *vm, njs_value_t *value); -njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_value_type_t type, +njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_prototype_t type, const njs_value_t *name, const njs_value_t *message); njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); diff -r b02b79e30d4a -r a908c2ef62ca src/njs_fs.c --- a/src/njs_fs.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_fs.c Thu Oct 24 16:17:16 2019 +0300 @@ -1028,7 +1028,7 @@ njs_fs_error(njs_vm_t *vm, const char *s return NJS_ERROR; } - error = njs_error_alloc(vm, NJS_OBJECT_ERROR, NULL, &string); + error = njs_error_alloc(vm, NJS_PROTOTYPE_ERROR, NULL, &string); if (njs_slow_path(error == NULL)) { return NJS_ERROR; } @@ -1101,7 +1101,7 @@ njs_fs_error(njs_vm_t *vm, const char *s } } - njs_set_type_object(retval, error, NJS_OBJECT_ERROR); + njs_set_object(retval, error); return NJS_ERROR; } diff -r b02b79e30d4a -r a908c2ef62ca src/njs_generator.c --- a/src/njs_generator.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_generator.c Thu Oct 24 16:17:16 2019 +0300 @@ -249,7 +249,8 @@ static njs_int_t njs_generate_function_d #define njs_generate_syntax_error(vm, node, fmt, ...) \ - njs_parser_node_error(vm, node, NJS_OBJECT_SYNTAX_ERROR, fmt, ##__VA_ARGS__) + njs_parser_node_error(vm, node, NJS_PROTOTYPE_SYNTAX_ERROR, fmt, \ + ##__VA_ARGS__) static const njs_str_t no_label = njs_str(""); diff -r b02b79e30d4a -r a908c2ef62ca src/njs_json.c --- a/src/njs_json.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_json.c Thu Oct 24 16:17:16 2019 +0300 @@ -2312,16 +2312,9 @@ njs_dump_value(njs_json_stringify_t *str /* Fall through. */ + case NJS_OBJECT: case NJS_REGEXP: case NJS_DATE: - case NJS_OBJECT_ERROR: - case NJS_OBJECT_EVAL_ERROR: - case NJS_OBJECT_INTERNAL_ERROR: - case NJS_OBJECT_RANGE_ERROR: - case NJS_OBJECT_REF_ERROR: - case NJS_OBJECT_SYNTAX_ERROR: - case NJS_OBJECT_TYPE_ERROR: - case NJS_OBJECT_URI_ERROR: switch (value->type) { case NJS_NUMBER: @@ -2366,7 +2359,7 @@ memory_error: #define njs_dump_is_object(value) \ - (((value)->type == NJS_OBJECT) \ + (((value)->type == NJS_OBJECT && !njs_object(value)->error_data) \ || ((value)->type == NJS_ARRAY) \ || ((value)->type == NJS_OBJECT_VALUE) \ || ((value)->type == NJS_EXTERNAL \ diff -r b02b79e30d4a -r a908c2ef62ca src/njs_module.c --- a/src/njs_module.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_module.c Thu Oct 24 16:17:16 2019 +0300 @@ -539,6 +539,7 @@ njs_module_require(njs_vm_t *vm, njs_val *object = module->object; object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; object->shared = 0; + object->error_data = 0; njs_set_object(&vm->retval, object); diff -r b02b79e30d4a -r a908c2ef62ca src/njs_object.c --- a/src/njs_object.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_object.c Thu Oct 24 16:17:16 2019 +0300 @@ -43,6 +43,7 @@ njs_object_alloc(njs_vm_t *vm) object->type = NJS_OBJECT; object->shared = 0; object->extensible = 1; + object->error_data = 0; return object; } @@ -2057,7 +2058,7 @@ njs_object_prototype_to_string(njs_vm_t { const njs_value_t *name; - static const njs_value_t *class_name[NJS_TYPE_MAX] = { + static const njs_value_t *class_name[NJS_VALUE_TYPE_MAX] = { /* Primitives. */ &njs_object_null_string, &njs_object_undefined_string, @@ -2086,19 +2087,15 @@ njs_object_prototype_to_string(njs_vm_t &njs_object_function_string, &njs_object_regexp_string, &njs_object_date_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, - &njs_object_error_string, &njs_object_object_string, }; name = class_name[args[0].type]; + if (njs_is_error(&args[0])) { + name = &njs_object_error_string; + } + if (njs_fast_path(name != NULL)) { vm->retval = *name; diff -r b02b79e30d4a -r a908c2ef62ca src/njs_parser.c --- a/src/njs_parser.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_parser.c Thu Oct 24 16:17:16 2019 +0300 @@ -2300,7 +2300,7 @@ njs_parser_trace_handler(njs_trace_t *tr static void njs_parser_scope_error(njs_vm_t *vm, njs_parser_scope_t *scope, - njs_value_type_t type, uint32_t line, const char *fmt, va_list args) + njs_prototype_t type, uint32_t line, const char *fmt, va_list args) { size_t width; u_char msg[NJS_MAX_ERROR_STR]; @@ -2333,7 +2333,7 @@ njs_parser_scope_error(njs_vm_t *vm, njs void njs_parser_lexer_error(njs_vm_t *vm, njs_parser_t *parser, - njs_value_type_t type, const char *fmt, ...) + njs_prototype_t type, const char *fmt, ...) { va_list args; @@ -2350,7 +2350,7 @@ njs_parser_lexer_error(njs_vm_t *vm, njs void njs_parser_node_error(njs_vm_t *vm, njs_parser_node_t *node, - njs_value_type_t type, const char *fmt, ...) + njs_prototype_t type, const char *fmt, ...) { va_list args; diff -r b02b79e30d4a -r a908c2ef62ca src/njs_parser.h --- a/src/njs_parser.h Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_parser.h Thu Oct 24 16:17:16 2019 +0300 @@ -109,9 +109,9 @@ njs_token_t njs_parser_unexpected_token( u_char *njs_parser_trace_handler(njs_trace_t *trace, njs_trace_data_t *td, u_char *start); void njs_parser_lexer_error(njs_vm_t *vm, njs_parser_t *parser, - njs_value_type_t type, const char *fmt, ...); + njs_prototype_t type, const char *fmt, ...); void njs_parser_node_error(njs_vm_t *vm, njs_parser_node_t *node, - njs_value_type_t type, const char *fmt, ...); + njs_prototype_t type, const char *fmt, ...); #define njs_parser_enter(vm, parser) \ @@ -155,12 +155,13 @@ void njs_parser_node_error(njs_vm_t *vm, #define njs_parser_syntax_error(vm, parser, fmt, ...) \ - njs_parser_lexer_error(vm, parser, NJS_OBJECT_SYNTAX_ERROR, fmt, \ + njs_parser_lexer_error(vm, parser, NJS_PROTOTYPE_SYNTAX_ERROR, fmt, \ ##__VA_ARGS__) #define njs_parser_ref_error(vm, parser, fmt, ...) \ - njs_parser_lexer_error(vm, parser, NJS_OBJECT_REF_ERROR, fmt, ##__VA_ARGS__) + njs_parser_lexer_error(vm, parser, NJS_PROTOTYPE_REF_ERROR, fmt, \ + ##__VA_ARGS__) njs_inline njs_token_t diff -r b02b79e30d4a -r a908c2ef62ca src/njs_value.c --- a/src/njs_value.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_value.c Thu Oct 24 16:17:16 2019 +0300 @@ -342,30 +342,6 @@ njs_type_string(njs_value_type_t type) case NJS_DATE: return "date"; - case NJS_OBJECT_ERROR: - return "error"; - - case NJS_OBJECT_EVAL_ERROR: - return "eval error"; - - case NJS_OBJECT_INTERNAL_ERROR: - return "internal error"; - - case NJS_OBJECT_RANGE_ERROR: - return "range error"; - - case NJS_OBJECT_REF_ERROR: - return "reference error"; - - case NJS_OBJECT_SYNTAX_ERROR: - return "syntax error"; - - case NJS_OBJECT_TYPE_ERROR: - return "type error"; - - case NJS_OBJECT_URI_ERROR: - return "uri error"; - default: return NULL; } @@ -558,14 +534,6 @@ njs_property_query(njs_vm_t *vm, njs_pro case NJS_OBJECT_STRING: case NJS_REGEXP: case NJS_DATE: - case NJS_OBJECT_ERROR: - case NJS_OBJECT_EVAL_ERROR: - case NJS_OBJECT_INTERNAL_ERROR: - case NJS_OBJECT_RANGE_ERROR: - case NJS_OBJECT_REF_ERROR: - case NJS_OBJECT_SYNTAX_ERROR: - case NJS_OBJECT_TYPE_ERROR: - case NJS_OBJECT_URI_ERROR: case NJS_OBJECT_VALUE: obj = njs_object(value); break; diff -r b02b79e30d4a -r a908c2ef62ca src/njs_value.h --- a/src/njs_value.h Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_value.h Thu Oct 24 16:17:16 2019 +0300 @@ -64,16 +64,8 @@ typedef enum { NJS_FUNCTION = 0x15, NJS_REGEXP = 0x16, NJS_DATE = 0x17, - NJS_OBJECT_ERROR = 0x18, - NJS_OBJECT_EVAL_ERROR = 0x19, - NJS_OBJECT_INTERNAL_ERROR = 0x1a, - NJS_OBJECT_RANGE_ERROR = 0x1b, - NJS_OBJECT_REF_ERROR = 0x1c, - NJS_OBJECT_SYNTAX_ERROR = 0x1d, - NJS_OBJECT_TYPE_ERROR = 0x1e, - NJS_OBJECT_URI_ERROR = 0x1f, - NJS_OBJECT_VALUE = 0x20, -#define NJS_TYPE_MAX (NJS_OBJECT_VALUE + 1) + NJS_OBJECT_VALUE = 0x18, +#define NJS_VALUE_TYPE_MAX (NJS_OBJECT_VALUE + 1) } njs_value_type_t; @@ -205,7 +197,9 @@ struct njs_object_s { /* The type is used in constructor prototypes. */ njs_value_type_t type:8; uint8_t shared; /* 1 bit */ - uint8_t extensible; /* 1 bit */ + + uint8_t extensible:1; + uint8_t error_data:1; }; @@ -459,10 +453,6 @@ typedef struct { #define njs_is_string(value) \ ((value)->type == NJS_STRING) -#define njs_is_error(value) \ - ((value)->type >= NJS_OBJECT_ERROR \ - && (value)->type <= NJS_OBJECT_URI_ERROR) - /* * The truth field coincides with short_string.size and short_string.length @@ -520,6 +510,11 @@ typedef struct { ((value)->type >= NJS_OBJECT) +#define njs_has_prototype(vm, value, proto) \ + (((njs_object_prototype_t *) \ + njs_object(value)->__proto__ - (vm)->prototypes) == proto) + + #define njs_is_object_value(value) \ ((value)->type == NJS_OBJECT_VALUE) @@ -552,6 +547,10 @@ typedef struct { ((value)->type == NJS_DATE) +#define njs_is_error(value) \ + ((value)->type == NJS_OBJECT && njs_object(value)->error_data) + + #define njs_is_external(value) \ ((value)->type == NJS_EXTERNAL) diff -r b02b79e30d4a -r a908c2ef62ca src/njs_vm.c --- a/src/njs_vm.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_vm.c Thu Oct 24 16:17:16 2019 +0300 @@ -675,7 +675,7 @@ njs_vm_value_error_set(njs_vm_t *vm, njs va_end(args); } - njs_error_new(vm, value, NJS_OBJECT_ERROR, buf, p - buf); + njs_error_new(vm, value, NJS_PROTOTYPE_ERROR, buf, p - buf); } @@ -1015,9 +1015,13 @@ njs_vm_value_to_string(njs_vm_t *vm, njs return NJS_ERROR; } - if (njs_slow_path(src->type == NJS_OBJECT_INTERNAL_ERROR)) { + if (njs_slow_path(njs_is_error(src))) { + /* MemoryError is a nonextensible internal error. */ - if (!njs_object(src)->extensible) { + + if (njs_has_prototype(vm, src, NJS_PROTOTYPE_INTERNAL_ERROR) + && !njs_object(src)->extensible) + { njs_string_get(&njs_string_memory_error, dst); return NJS_OK; } diff -r b02b79e30d4a -r a908c2ef62ca src/njs_vm.h --- a/src/njs_vm.h Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_vm.h Thu Oct 24 16:17:16 2019 +0300 @@ -81,7 +81,7 @@ typedef enum { (((index) & NJS_SCOPE_CALLEE_ARGUMENTS) == NJS_SCOPE_CALLEE_ARGUMENTS) -enum njs_prototypes_e { +typedef enum { NJS_PROTOTYPE_OBJECT = 0, NJS_PROTOTYPE_ARRAY, NJS_PROTOTYPE_BOOLEAN, @@ -101,7 +101,7 @@ enum njs_prototypes_e { NJS_PROTOTYPE_TYPE_ERROR, NJS_PROTOTYPE_URI_ERROR, #define NJS_PROTOTYPE_MAX (NJS_PROTOTYPE_URI_ERROR + 1) -}; +} njs_prototype_t; #define njs_primitive_prototype_index(type) \ @@ -266,7 +266,7 @@ struct njs_vm_s { /* * MemoryError is statically allocated immutable Error object - * with the generic type NJS_OBJECT_INTERNAL_ERROR. + * with the InternalError prototype. */ njs_object_t memory_error_object; diff -r b02b79e30d4a -r a908c2ef62ca src/njs_vmcode.c --- a/src/njs_vmcode.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/njs_vmcode.c Thu Oct 24 16:17:16 2019 +0300 @@ -1384,7 +1384,7 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_valu { /* ECMAScript 5.1: null, array and regexp are objects. */ - static const njs_value_t *types[NJS_TYPE_MAX] = { + static const njs_value_t *types[NJS_VALUE_TYPE_MAX] = { &njs_string_object, &njs_string_undefined, &njs_string_boolean, @@ -1411,14 +1411,6 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_valu &njs_string_object, &njs_string_object, &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, - &njs_string_object, }; vm->retval = *types[value->type]; diff -r b02b79e30d4a -r a908c2ef62ca src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 24 16:15:01 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 24 16:17:16 2019 +0300 @@ -8670,6 +8670,9 @@ static njs_unit_test_t njs_test[] = { njs_str("RangeError('e')"), njs_str("RangeError: e") }, + { njs_str("var e = RangeError('e'); Object.preventExtensions(e);e"), + njs_str("RangeError: e") }, + { njs_str("ReferenceError('e')"), njs_str("ReferenceError: e") }, @@ -9532,6 +9535,9 @@ static njs_unit_test_t njs_test[] = { njs_str("Object.prototype.toString.call(new URIError)"), njs_str("[object Error]") }, + { njs_str("Object.prototype.toString.call(URIError.prototype)"), + njs_str("[object Object]") }, + { njs_str("Object.prototype"), njs_str("[object Object]") }, @@ -10264,6 +10270,9 @@ static njs_unit_test_t njs_test[] = { njs_str("var fn = (function() { return new Function('return this'); }).call({}), o = {}; fn.call(o) == o && fn.bind(o).call(this) == o"), njs_str("true") }, + { njs_str("this.NN = {}; var f = Function('eval = 42;'); f()"), + njs_str("SyntaxError: Identifier \"eval\" is forbidden as left-hand in assignment in runtime:1") }, + { njs_str("RegExp()"), njs_str("/(?:)/") }, @@ -14029,6 +14038,9 @@ static njs_unit_test_t njs_test[] = { njs_str("njs.dump({a:1, b:[1,,2,{c:new Boolean(1)}]})"), njs_str("{a:1,b:[1,,2,{c:[Boolean: true]}]}") }, + { njs_str("njs.dump([InternalError(),TypeError('msg'), new RegExp(), /^undef$/m, new Date(0)])"), + njs_str("[InternalError,TypeError: msg,/(?:)/,/^undef$/m,1970-01-01T00:00:00.000Z]") }, + { njs_str("njs.dump(Array.prototype.slice.call({'1':'b', length:2}))"), njs_str("[,'b']") }, From xeioex at nginx.com Thu Oct 24 13:24:27 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 24 Oct 2019 13:24:27 +0000 Subject: [njs] Fixed [[Prototype]] slot of NativeErrors. Message-ID: details: https://hg.nginx.org/njs/rev/84cb3fa5d1cc branches: changeset: 1200:84cb3fa5d1cc user: Dmitry Volyntsev date: Thu Oct 24 16:17:16 2019 +0300 description: Fixed [[Prototype]] slot of NativeErrors. diffstat: src/njs_builtin.c | 86 +++++++++------- src/test/njs_unit_test.c | 227 ++++++---------------------------------------- 2 files changed, 81 insertions(+), 232 deletions(-) diffs (405 lines): diff -r a908c2ef62ca -r 84cb3fa5d1cc src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 24 16:17:16 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 24 16:17:16 2019 +0300 @@ -318,6 +318,7 @@ njs_builtin_objects_create(njs_vm_t *vm) for (p = njs_constructor_init; *p != NULL; p++) { obj = *p; + func->object.type = NJS_FUNCTION; func->object.shared = 0; func->object.extensible = 1; func->native = 1; @@ -351,76 +352,76 @@ njs_prototype_function(njs_vm_t *vm, njs /* * Object(), - * Object.__proto__ -> Function_Prototype, - * Object_Prototype.__proto__ -> null, + * Object.__proto__ -> Function.prototype, + * Object.prototype.__proto__ -> null, * the null value is handled by njs_object_prototype_proto(), * * Array(), - * Array.__proto__ -> Function_Prototype, - * Array_Prototype.__proto__ -> Object_Prototype, + * Array.__proto__ -> Function.prototype, + * Array.prototype.__proto__ -> Object.prototype, * * Boolean(), - * Boolean.__proto__ -> Function_Prototype, - * Boolean_Prototype.__proto__ -> Object_Prototype, + * Boolean.__proto__ -> Function.prototype, + * Boolean.prototype.__proto__ -> Object.prototype, * * Number(), - * Number.__proto__ -> Function_Prototype, - * Number_Prototype.__proto__ -> Object_Prototype, + * Number.__proto__ -> Function.prototype, + * Number.prototype.__proto__ -> Object.prototype, * * String(), - * String.__proto__ -> Function_Prototype, - * String_Prototype.__proto__ -> Object_Prototype, + * String.__proto__ -> Function.prototype, + * String.prototype.__proto__ -> Object.prototype, * * Function(), - * Function.__proto__ -> Function_Prototype, - * Function_Prototype.__proto__ -> Object_Prototype, + * Function.__proto__ -> Function.prototype, + * Function.prototype.__proto__ -> Object.prototype, * * RegExp(), - * RegExp.__proto__ -> Function_Prototype, - * RegExp_Prototype.__proto__ -> Object_Prototype, + * RegExp.__proto__ -> Function.prototype, + * RegExp.prototype.__proto__ -> Object.prototype, * * Date(), - * Date.__proto__ -> Function_Prototype, - * Date_Prototype.__proto__ -> Object_Prototype, + * Date.__proto__ -> Function.prototype, + * Date.prototype.__proto__ -> Object.prototype, * * Error(), - * Error.__proto__ -> Function_Prototype, - * Error_Prototype.__proto__ -> Object_Prototype, + * Error.__proto__ -> Function.prototype, + * Error.prototype.__proto__ -> Object.prototype, * * EvalError(), - * EvalError.__proto__ -> Function_Prototype, - * EvalError_Prototype.__proto__ -> Error_Prototype, + * EvalError.__proto__ -> Error, + * EvalError.prototype.__proto__ -> Error.prototype, * * InternalError(), - * InternalError.__proto__ -> Function_Prototype, - * InternalError_Prototype.__proto__ -> Error_Prototype, + * InternalError.__proto__ -> Error, + * InternalError.prototype.__proto__ -> Error.prototype, * * RangeError(), - * RangeError.__proto__ -> Function_Prototype, - * RangeError_Prototype.__proto__ -> Error_Prototype, + * RangeError.__proto__ -> Error, + * RangeError.prototype.__proto__ -> Error.prototype, * * ReferenceError(), - * ReferenceError.__proto__ -> Function_Prototype, - * ReferenceError_Prototype.__proto__ -> Error_Prototype, + * ReferenceError.__proto__ -> Error, + * ReferenceError.prototype.__proto__ -> Error.prototype, * * SyntaxError(), - * SyntaxError.__proto__ -> Function_Prototype, - * SyntaxError_Prototype.__proto__ -> Error_Prototype, + * SyntaxError.__proto__ -> Error, + * SyntaxError.prototype.__proto__ -> Error.prototype, * * TypeError(), - * TypeError.__proto__ -> Function_Prototype, - * TypeError_Prototype.__proto__ -> Error_Prototype, + * TypeError.__proto__ -> Error, + * TypeError.prototype.__proto__ -> Error.prototype, * * URIError(), - * URIError.__proto__ -> Function_Prototype, - * URIError_Prototype.__proto__ -> Error_Prototype, + * URIError.__proto__ -> Error, + * URIError.prototype.__proto__ -> Error.prototype, * * MemoryError(), - * MemoryError.__proto__ -> Function_Prototype, - * MemoryError_Prototype.__proto__ -> Error_Prototype, + * MemoryError.__proto__ -> Error, + * MemoryError.prototype.__proto__ -> Error.prototype, * * eval(), - * eval.__proto__ -> Function_Prototype. + * eval.__proto__ -> Function.prototype. */ njs_int_t @@ -429,7 +430,8 @@ njs_builtin_objects_clone(njs_vm_t *vm, size_t size; njs_uint_t i; njs_value_t *values; - njs_object_t *object_prototype, *function_prototype, *error_prototype; + njs_object_t *object_prototype, *function_prototype, *error_prototype, + *error_constructor; /* * Copy both prototypes and constructors arrays by one memcpy() @@ -452,14 +454,22 @@ njs_builtin_objects_clone(njs_vm_t *vm, vm->prototypes[i].object.__proto__ = error_prototype; } - function_prototype = &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; values = vm->scopes[NJS_SCOPE_GLOBAL]; - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { + function_prototype = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; + + for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_EVAL_ERROR; i++) { njs_set_function(&values[i], &vm->constructors[i]); vm->constructors[i].object.__proto__ = function_prototype; } + error_constructor = &vm->constructors[NJS_CONSTRUCTOR_ERROR].object; + + for (i = NJS_CONSTRUCTOR_EVAL_ERROR; i < NJS_CONSTRUCTOR_MAX; i++) { + njs_set_function(&values[i], &vm->constructors[i]); + vm->constructors[i].object.__proto__ = error_constructor; + } + vm->global_object = vm->shared->objects[0]; vm->global_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; vm->global_object.shared = 0; diff -r a908c2ef62ca -r 84cb3fa5d1cc src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 24 16:17:16 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 24 16:17:16 2019 +0300 @@ -8661,75 +8661,9 @@ static njs_unit_test_t njs_test[] = "new Error()"), njs_str("n: m") }, - { njs_str("EvalError('e')"), - njs_str("EvalError: e") }, - - { njs_str("InternalError('e')"), - njs_str("InternalError: e") }, - - { njs_str("RangeError('e')"), - njs_str("RangeError: e") }, - { njs_str("var e = RangeError('e'); Object.preventExtensions(e);e"), njs_str("RangeError: e") }, - { njs_str("ReferenceError('e')"), - njs_str("ReferenceError: e") }, - - { njs_str("SyntaxError('e')"), - njs_str("SyntaxError: e") }, - - { njs_str("TypeError('e')"), - njs_str("TypeError: e") }, - - { njs_str("URIError('e')"), - njs_str("URIError: e") }, - - { njs_str("MemoryError('e')"), - njs_str("MemoryError") }, - - { njs_str("EvalError('e').name + ': ' + EvalError('e').message"), - njs_str("EvalError: e") }, - - { njs_str("InternalError('e').name + ': ' + InternalError('e').message"), - njs_str("InternalError: e") }, - - { njs_str("RangeError('e').name + ': ' + RangeError('e').message"), - njs_str("RangeError: e") }, - - { njs_str("ReferenceError('e').name + ': ' + ReferenceError('e').message"), - njs_str("ReferenceError: e") }, - - { njs_str("SyntaxError('e').name + ': ' + SyntaxError('e').message"), - njs_str("SyntaxError: e") }, - - { njs_str("TypeError('e').name + ': ' + TypeError('e').message"), - njs_str("TypeError: e") }, - - { njs_str("URIError('e').name + ': ' + URIError('e').message"), - njs_str("URIError: e") }, - - { njs_str("var e = EvalError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = InternalError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = RangeError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = ReferenceError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = SyntaxError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = TypeError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - - { njs_str("var e = URIError('e'); e.name = 'E'; e"), - njs_str("E: e") }, - /* Memory object is immutable. */ { njs_str("var e = MemoryError('e'); e.name = 'E'"), @@ -8759,134 +8693,39 @@ static njs_unit_test_t njs_test[] = { njs_str("MemoryError.prototype.name"), njs_str("InternalError") }, - { njs_str("EvalError.prototype.message"), - njs_str("") }, - - { njs_str("InternalError.prototype.message"), - njs_str("") }, - - { njs_str("RangeError.prototype.message"), - njs_str("") }, - - { njs_str("ReferenceError.prototype.message"), - njs_str("") }, - - { njs_str("SyntaxError.prototype.message"), - njs_str("") }, - - { njs_str("TypeError.prototype.message"), - njs_str("") }, - - { njs_str("URIError.prototype.message"), - njs_str("") }, - - { njs_str("MemoryError.prototype.message"), - njs_str("") }, - - { njs_str("EvalError.prototype.constructor == EvalError"), - njs_str("true") }, - - { njs_str("RangeError.prototype.constructor == RangeError"), - njs_str("true") }, - - { njs_str("ReferenceError.prototype.constructor == ReferenceError"), - njs_str("true") }, - - { njs_str("SyntaxError.prototype.constructor == SyntaxError"), - njs_str("true") }, - - { njs_str("TypeError.prototype.constructor == TypeError"), - njs_str("true") }, - - { njs_str("URIError.prototype.constructor == URIError"), - njs_str("true") }, - - { njs_str("EvalError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("RangeError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("ReferenceError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("SyntaxError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("TypeError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("URIError.prototype.hasOwnProperty('constructor')"), - njs_str("true") }, - - { njs_str("EvalError().__proto__ == EvalError.prototype"), - njs_str("true") }, - - { njs_str("RangeError().__proto__ == RangeError.prototype"), - njs_str("true") }, - - { njs_str("ReferenceError().__proto__ == ReferenceError.prototype"), - njs_str("true") }, - - { njs_str("SyntaxError().__proto__ == SyntaxError.prototype"), - njs_str("true") }, - - { njs_str("TypeError().__proto__ == TypeError.prototype"), - njs_str("true") }, - - { njs_str("URIError().__proto__ == URIError.prototype"), - njs_str("true") }, - - { njs_str("EvalError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("RangeError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("ReferenceError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("SyntaxError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("TypeError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("URIError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("MemoryError().__proto__ == MemoryError.prototype"), - njs_str("true") }, - - { njs_str("MemoryError().__proto__.__proto__ == Error.prototype"), - njs_str("true") }, - - { njs_str("typeof Error()"), - njs_str("object") }, - - { njs_str("typeof EvalError()"), - njs_str("object") }, - - { njs_str("typeof InternalError()"), - njs_str("object") }, - - { njs_str("typeof RangeError()"), - njs_str("object") }, - - { njs_str("typeof ReferenceError()"), - njs_str("object") }, - - { njs_str("typeof SyntaxError()"), - njs_str("object") }, - - { njs_str("typeof TypeError()"), - njs_str("object") }, - - { njs_str("typeof URIError()"), - njs_str("object") }, - - { njs_str("typeof MemoryError()"), - njs_str("object") }, + + /* NativeErrors. */ + + { njs_str( + "function isValidNativeError(e) {" + " var inst;" + " var proto = Object.getPrototypeOf(e) === Error;" + " var proto2 = e.__proto__ === Error;" + " var iproto = e().__proto__ === e.prototype;" + " var iproto2 = e().__proto__.__proto__ === Error.prototype;" + " var tpof = typeof e() === 'object';" + " var ctor = e.prototype.constructor === e;" + " var msg = e.prototype.message === '';" + " var name = e('e').toString() === `${e.prototype.name}: e`;" + " var name2 = (inst = e('e'), inst.name = 'E', inst.toString() === 'E: e');" + " var name3 = (inst = e('e'), inst.name = '', inst.toString() === 'e');" + " var name4 = e().toString() === `${e.prototype.name}`;" + " var own_proto_ctor = e.prototype.hasOwnProperty('constructor');" + "" + " return proto && proto2 && iproto && iproto2 " + " && tpof && ctor && msg && name && name2 && name3 && name4 " + " && own_proto_ctor;" + "};" + "[" + " EvalError," + " InternalError," + " RangeError," + " ReferenceError," + " SyntaxError," + " TypeError," + " URIError," + "].every(e => isValidNativeError(e))"), + njs_str("true") }, /* Exceptions. */ From xeioex at nginx.com Thu Oct 24 13:24:28 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 24 Oct 2019 13:24:28 +0000 Subject: [njs] Fixed NativeError.prototype.message properties. Message-ID: details: https://hg.nginx.org/njs/rev/d849bf348b0d branches: changeset: 1201:d849bf348b0d user: Dmitry Volyntsev date: Thu Oct 24 16:17:17 2019 +0300 description: Fixed NativeError.prototype.message properties. diffstat: src/njs_error.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 4 ++- test/njs_expect_test.exp | 3 ++ 3 files changed, 62 insertions(+), 1 deletions(-) diffs (139 lines): diff -r 84cb3fa5d1cc -r d849bf348b0d src/njs_error.c --- a/src/njs_error.c Thu Oct 24 16:17:16 2019 +0300 +++ b/src/njs_error.c Thu Oct 24 16:17:17 2019 +0300 @@ -779,6 +779,14 @@ static const njs_object_prop_t njs_eval }, { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { .type = NJS_PROPERTY_HANDLER, .name = njs_string("constructor"), .value = njs_prop_handler(njs_object_prototype_create_constructor), @@ -827,6 +835,14 @@ static const njs_object_prop_t njs_inte { .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, .name = njs_string("toString"), .value = njs_native_function(njs_internal_error_prototype_to_string, 0), .writable = 1, @@ -853,6 +869,14 @@ static const njs_object_prop_t njs_rang }, { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { .type = NJS_PROPERTY_HANDLER, .name = njs_string("constructor"), .value = njs_prop_handler(njs_object_prototype_create_constructor), @@ -880,6 +904,14 @@ static const njs_object_prop_t njs_refe }, { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { .type = NJS_PROPERTY_HANDLER, .name = njs_string("constructor"), .value = njs_prop_handler(njs_object_prototype_create_constructor), @@ -907,6 +939,14 @@ static const njs_object_prop_t njs_synt }, { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { .type = NJS_PROPERTY_HANDLER, .name = njs_string("constructor"), .value = njs_prop_handler(njs_object_prototype_create_constructor), @@ -934,6 +974,14 @@ static const njs_object_prop_t njs_type }, { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { .type = NJS_PROPERTY_HANDLER, .name = njs_string("constructor"), .value = njs_prop_handler(njs_object_prototype_create_constructor), @@ -962,6 +1010,14 @@ static const njs_object_prop_t njs_uri_ { .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, .name = njs_string("name"), .value = njs_string("URIError"), .writable = 1, diff -r 84cb3fa5d1cc -r d849bf348b0d src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 24 16:17:16 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 24 16:17:17 2019 +0300 @@ -8710,11 +8710,13 @@ static njs_unit_test_t njs_test[] = " var name2 = (inst = e('e'), inst.name = 'E', inst.toString() === 'E: e');" " var name3 = (inst = e('e'), inst.name = '', inst.toString() === 'e');" " var name4 = e().toString() === `${e.prototype.name}`;" + " var name_prop = Object.getOwnPropertyDescriptor(e.prototype, 'message');" + " name_prop = name_prop.writable && !name_prop.enumerable && name_prop.configurable;" " var own_proto_ctor = e.prototype.hasOwnProperty('constructor');" "" " return proto && proto2 && iproto && iproto2 " " && tpof && ctor && msg && name && name2 && name3 && name4 " - " && own_proto_ctor;" + " && name_prop && own_proto_ctor;" "};" "[" " EvalError," diff -r 84cb3fa5d1cc -r d849bf348b0d test/njs_expect_test.exp --- a/test/njs_expect_test.exp Thu Oct 24 16:17:16 2019 +0300 +++ b/test/njs_expect_test.exp Thu Oct 24 16:17:17 2019 +0300 @@ -766,6 +766,9 @@ njs_test { "Error: loading exception\r\n at module \\(loading_exception.js:1\\)"} {"import lib3 from 'lib1.js'\r\n" "undefined\r\n"} +} "-p test/module/" + +njs_test { {"import m from 'export_name.js'\r\n" "undefined\r\n"} {"m.prod(3,4)\r\n" From i at morfi.ru Thu Oct 24 13:38:38 2019 From: i at morfi.ru (i at morfi.ru) Date: Thu, 24 Oct 2019 13:38:38 +0000 Subject: [PATCH] Fix ngx_max_sockets variable, set actual value after use setrlimit(RLIMIT_NOFILE) Message-ID: # HG changeset patch # User Andrey Kolyshkin # Date 1571924112 -10800 # Thu Oct 24 16:35:12 2019 +0300 # Node ID dfae615e676214a83b91abfbb51c334cfb1ecfdd # Parent 89adf49fe76ada86d84e2af8f5cee9ca8c3dca19 Fix ngx_max_sockets variable, set actual value after use setrlimit(RLIMIT_NOFILE) diff -r 89adf49fe76a -r dfae615e6762 src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c Mon Oct 21 20:22:30 2019 +0300 +++ b/src/os/unix/ngx_process_cycle.c Thu Oct 24 16:35:12 2019 +0300 @@ -811,6 +811,8 @@ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); + } else { + ngx_max_sockets = ccf->rlimit_nofile; } } From mdounin at mdounin.ru Thu Oct 24 15:53:35 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 24 Oct 2019 18:53:35 +0300 Subject: [PATCH] Fix ngx_max_sockets variable, set actual value after use setrlimit(RLIMIT_NOFILE) In-Reply-To: References: Message-ID: <20191024155334.GD1877@mdounin.ru> Hello! On Thu, Oct 24, 2019 at 01:38:38PM +0000, i at morfi.ru wrote: > # HG changeset patch > # User Andrey Kolyshkin > # Date 1571924112 -10800 > # Thu Oct 24 16:35:12 2019 +0300 > # Node ID dfae615e676214a83b91abfbb51c334cfb1ecfdd > # Parent 89adf49fe76ada86d84e2af8f5cee9ca8c3dca19 > Fix ngx_max_sockets variable, set actual value after use setrlimit(RLIMIT_NOFILE) > > diff -r 89adf49fe76a -r dfae615e6762 src/os/unix/ngx_process_cycle.c > --- a/src/os/unix/ngx_process_cycle.c Mon Oct 21 20:22:30 2019 +0300 > +++ b/src/os/unix/ngx_process_cycle.c Thu Oct 24 16:35:12 2019 +0300 > @@ -811,6 +811,8 @@ > ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > "setrlimit(RLIMIT_NOFILE, %i) failed", > ccf->rlimit_nofile); > + } else { > + ngx_max_sockets = ccf->rlimit_nofile; > } > } > I'm not what the intended semantics of the ngx_max_sockets variable is, but given that it is not used - I don't think it matters, and the existing semantics of being rlimit_nofile at the time of nginx start is good enough. On the other hand, the change suggested breaks any possible intended semantics, as successful setrlimit() does not mean that the specified limit was actually applied. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Fri Oct 25 13:20:50 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 25 Oct 2019 13:20:50 +0000 Subject: [njs] Optimizing njs_vm_clone() for speed. Message-ID: details: https://hg.nginx.org/njs/rev/7e7d0dac4572 branches: changeset: 1202:7e7d0dac4572 user: Dmitry Volyntsev date: Fri Oct 25 16:20:37 2019 +0300 description: Optimizing njs_vm_clone() for speed. Postponing allocation of structures where possible. diffstat: src/njs_builtin.c | 34 ++++++- src/njs_extern.c | 13 ++- src/njs_vm.c | 224 ++++++++++++++++++----------------------------------- src/njs_vmcode.c | 2 +- 4 files changed, 120 insertions(+), 153 deletions(-) diffs (427 lines): diff -r d849bf348b0d -r 7e7d0dac4572 src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 24 16:17:17 2019 +0300 +++ b/src/njs_builtin.c Fri Oct 25 16:20:37 2019 +0300 @@ -183,13 +183,34 @@ njs_builtin_objects_create(njs_vm_t *vm) njs_function_t *func; njs_vm_shared_t *shared; njs_lvlhsh_query_t lhq; + njs_regexp_pattern_t *pattern; njs_object_prototype_t *prototype; const njs_object_init_t *obj, **p; const njs_function_init_t *f; static const njs_str_t sandbox_key = njs_str("sandbox"); - shared = vm->shared; + shared = njs_mp_zalloc(vm->mem_pool, sizeof(njs_vm_shared_t)); + if (njs_slow_path(shared == NULL)) { + return NJS_ERROR; + } + + njs_lvlhsh_init(&shared->keywords_hash); + + ret = njs_lexer_keywords_init(vm->mem_pool, &shared->keywords_hash); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + njs_lvlhsh_init(&shared->values_hash); + + pattern = njs_regexp_pattern_create(vm, (u_char *) "(?:)", + njs_length("(?:)"), 0); + if (njs_slow_path(pattern == NULL)) { + return NJS_ERROR; + } + + shared->empty_regexp_pattern = pattern; ret = njs_object_hash_init(vm, &shared->array_instance_hash, &njs_array_instance_init); @@ -242,6 +263,8 @@ njs_builtin_objects_create(njs_vm_t *vm) return NJS_ERROR; } + njs_lvlhsh_init(&vm->modules_hash); + lhq.replace = 0; lhq.pool = vm->mem_pool; @@ -302,15 +325,14 @@ njs_builtin_objects_create(njs_vm_t *vm) } shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = - vm->shared->empty_regexp_pattern; + shared->empty_regexp_pattern; string_object = &shared->string_object; njs_lvlhsh_init(&string_object->hash); - string_object->shared_hash = vm->shared->string_instance_hash; + string_object->shared_hash = shared->string_instance_hash; string_object->type = NJS_OBJECT_STRING; string_object->shared = 1; string_object->extensible = 0; - string_object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object; f = njs_native_constructors; func = shared->constructors; @@ -336,6 +358,8 @@ njs_builtin_objects_create(njs_vm_t *vm) func++; } + vm->shared = shared; + return NJS_OK; } @@ -471,7 +495,7 @@ njs_builtin_objects_clone(njs_vm_t *vm, } vm->global_object = vm->shared->objects[0]; - vm->global_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + vm->global_object.__proto__ = object_prototype; vm->global_object.shared = 0; njs_set_object(global, &vm->global_object); diff -r d849bf348b0d -r 7e7d0dac4572 src/njs_extern.c --- a/src/njs_extern.c Thu Oct 24 16:17:17 2019 +0300 +++ b/src/njs_extern.c Fri Oct 25 16:20:37 2019 +0300 @@ -171,12 +171,23 @@ njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *ext_val, const njs_extern_t *proto, njs_external_ptr_t object) { - void *obj; + void *obj; + njs_arr_t *externals; if (njs_slow_path(proto == NULL)) { return NJS_ERROR; } + if (njs_slow_path(vm->external_objects == NULL)) { + externals = njs_arr_create(vm->mem_pool, 4, sizeof(void *)); + if (njs_slow_path(externals == NULL)) { + return NJS_ERROR; + } + + vm->external_objects = externals; + } + + obj = njs_arr_add(vm->external_objects); if (njs_slow_path(obj == NULL)) { return NJS_ERROR; diff -r d849bf348b0d -r 7e7d0dac4572 src/njs_vm.c --- a/src/njs_vm.c Thu Oct 24 16:17:17 2019 +0300 +++ b/src/njs_vm.c Fri Oct 25 16:20:37 2019 +0300 @@ -22,11 +22,10 @@ const njs_str_t njs_entry_anonymous = njs_vm_t * njs_vm_create(njs_vm_opt_t *options) { - njs_mp_t *mp; - njs_vm_t *vm; - njs_int_t ret; - njs_arr_t *debug; - njs_regexp_pattern_t *pattern; + njs_mp_t *mp; + njs_vm_t *vm; + njs_int_t ret; + njs_arr_t *debug; mp = njs_mp_fast_create(2 * njs_pagesize(), 128, 512, 16); if (njs_slow_path(mp == NULL)) { @@ -34,86 +33,63 @@ njs_vm_create(njs_vm_opt_t *options) } vm = njs_mp_zalign(mp, sizeof(njs_value_t), sizeof(njs_vm_t)); + if (njs_slow_path(vm == NULL)) { + return NULL; + } - if (njs_fast_path(vm != NULL)) { - vm->mem_pool = mp; + vm->mem_pool = mp; + + ret = njs_regexp_init(vm); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + vm->options = *options; + + if (options->shared != NULL) { + vm->shared = options->shared; + + } else { + ret = njs_builtin_objects_create(vm); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + } + + njs_lvlhsh_init(&vm->values_hash); - ret = njs_regexp_init(vm); - if (njs_slow_path(ret != NJS_OK)) { + vm->external = options->external; + + vm->external_objects = njs_arr_create(vm->mem_pool, 4, sizeof(void *)); + if (njs_slow_path(vm->external_objects == NULL)) { + return NULL; + } + + njs_lvlhsh_init(&vm->externals_hash); + njs_lvlhsh_init(&vm->external_prototypes_hash); + + vm->trace.level = NJS_LEVEL_TRACE; + vm->trace.size = 2048; + vm->trace.handler = njs_parser_trace_handler; + vm->trace.data = vm; + + njs_set_undefined(&vm->retval); + + if (options->backtrace) { + debug = njs_arr_create(vm->mem_pool, 4, + sizeof(njs_function_debug_t)); + if (njs_slow_path(debug == NULL)) { return NULL; } - vm->options = *options; - - if (options->shared != NULL) { - vm->shared = options->shared; - - } else { - vm->shared = njs_mp_zalloc(mp, sizeof(njs_vm_shared_t)); - if (njs_slow_path(vm->shared == NULL)) { - return NULL; - } - - options->shared = vm->shared; - - njs_lvlhsh_init(&vm->shared->keywords_hash); - - ret = njs_lexer_keywords_init(mp, &vm->shared->keywords_hash); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - - njs_lvlhsh_init(&vm->shared->values_hash); - - pattern = njs_regexp_pattern_create(vm, (u_char *) "(?:)", - njs_length("(?:)"), 0); - if (njs_slow_path(pattern == NULL)) { - return NULL; - } - - vm->shared->empty_regexp_pattern = pattern; - - njs_lvlhsh_init(&vm->modules_hash); + vm->debug = debug; + } - ret = njs_builtin_objects_create(vm); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - } - - njs_lvlhsh_init(&vm->values_hash); - - vm->external = options->external; - - vm->external_objects = njs_arr_create(vm->mem_pool, 4, sizeof(void *)); - if (njs_slow_path(vm->external_objects == NULL)) { + if (options->accumulative) { + ret = njs_vm_init(vm); + if (njs_slow_path(ret != NJS_OK)) { return NULL; } - - njs_lvlhsh_init(&vm->externals_hash); - njs_lvlhsh_init(&vm->external_prototypes_hash); - - vm->trace.level = NJS_LEVEL_TRACE; - vm->trace.size = 2048; - vm->trace.handler = njs_parser_trace_handler; - vm->trace.data = vm; - - if (options->backtrace) { - debug = njs_arr_create(vm->mem_pool, 4, - sizeof(njs_function_debug_t)); - if (njs_slow_path(debug == NULL)) { - return NULL; - } - - vm->debug = debug; - } - - if (options->accumulative) { - ret = njs_vm_init(vm); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - } } return vm; @@ -243,9 +219,7 @@ njs_vm_clone(njs_vm_t *vm, njs_external_ { njs_mp_t *nmp; njs_vm_t *nvm; - uint32_t items; njs_int_t ret; - njs_arr_t *externals; njs_thread_log_debug("CLONE:"); @@ -258,58 +232,23 @@ njs_vm_clone(njs_vm_t *vm, njs_external_ return NULL; } - nvm = njs_mp_zalign(nmp, sizeof(njs_value_t), sizeof(njs_vm_t)); - - if (njs_fast_path(nvm != NULL)) { - nvm->mem_pool = nmp; - - nvm->shared = vm->shared; - - nvm->trace = vm->trace; - nvm->trace.data = nvm; - - nvm->variables_hash = vm->variables_hash; - nvm->values_hash = vm->values_hash; + nvm = njs_mp_align(nmp, sizeof(njs_value_t), sizeof(njs_vm_t)); + if (njs_slow_path(nvm == NULL)) { + goto fail; + } - nvm->modules = vm->modules; - nvm->modules_hash = vm->modules_hash; - - nvm->externals_hash = vm->externals_hash; - nvm->external_prototypes_hash = vm->external_prototypes_hash; - - items = vm->external_objects->items; - - externals = njs_arr_create(nvm->mem_pool, items + 4, sizeof(void *)); - if (njs_slow_path(externals == NULL)) { - return NULL; - } + *nvm = *vm; - if (items > 0) { - memcpy(externals->start, vm->external_objects->start, - items * sizeof(void *)); - externals->items = items; - } - - nvm->external_objects = externals; - - nvm->options = vm->options; - - nvm->start = vm->start; + nvm->mem_pool = nmp; + nvm->trace.data = nvm; + nvm->external = external; - nvm->external = external; - - nvm->global_scope = vm->global_scope; - nvm->scope_size = vm->scope_size; - - nvm->debug = vm->debug; + ret = njs_vm_init(nvm); + if (njs_slow_path(ret != NJS_OK)) { + goto fail; + } - ret = njs_vm_init(nvm); - if (njs_slow_path(ret != NJS_OK)) { - goto fail; - } - - return nvm; - } + return nvm; fail: @@ -325,7 +264,6 @@ njs_vm_init(njs_vm_t *vm) size_t size, scope_size; u_char *values; njs_int_t ret; - njs_arr_t *backtrace; njs_value_t *global; njs_frame_t *frame; @@ -353,10 +291,7 @@ njs_vm_init(njs_vm_t *vm) vm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values; - if (vm->global_scope != 0) { - memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, - vm->scope_size); - } + memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, vm->scope_size); ret = njs_regexp_init(vm); if (njs_slow_path(ret != NJS_OK)) { @@ -373,20 +308,6 @@ njs_vm_init(njs_vm_t *vm) njs_lvlhsh_init(&vm->events_hash); njs_queue_init(&vm->posted_events); - if (vm->debug != NULL) { - backtrace = njs_arr_create(vm->mem_pool, 4, - sizeof(njs_backtrace_entry_t)); - if (njs_slow_path(backtrace == NULL)) { - return NJS_ERROR; - } - - vm->backtrace = backtrace; - } - - if (njs_is_null(&vm->retval)) { - njs_set_undefined(&vm->retval); - } - return NJS_OK; } @@ -1101,6 +1022,7 @@ njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame) { njs_int_t ret; + njs_arr_t *backtrace; njs_uint_t i; njs_function_t *function; njs_native_frame_t *native_frame; @@ -1108,6 +1030,16 @@ njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_function_lambda_t *lambda; njs_backtrace_entry_t *be; + if (njs_slow_path(vm->backtrace == NULL)) { + backtrace = njs_arr_create(vm->mem_pool, 4, + sizeof(njs_backtrace_entry_t)); + if (njs_slow_path(backtrace == NULL)) { + return NJS_ERROR; + } + + vm->backtrace = backtrace; + } + native_frame = &frame->native; function = native_frame->function; diff -r d849bf348b0d -r 7e7d0dac4572 src/njs_vmcode.c --- a/src/njs_vmcode.c Thu Oct 24 16:17:17 2019 +0300 +++ b/src/njs_vmcode.c Fri Oct 25 16:20:37 2019 +0300 @@ -896,7 +896,7 @@ error: if (catch != NULL) { pc = catch; - if (vm->debug != NULL) { + if (vm->backtrace != NULL) { njs_arr_reset(vm->backtrace); } From qiyingwangwqy at gmail.com Mon Oct 28 07:25:27 2019 From: qiyingwangwqy at gmail.com (Qiying Wang) Date: Mon, 28 Oct 2019 15:25:27 +0800 Subject: Why does ngx_epoll_del_event use EPOLL_CTL_MOD Message-ID: Hello! ngx_epoll_del_event is a function to delete an event. Deleting an event means unregister the file descriptor from epoll therefore it would not be triggered unless being added again. But EPOLL_CTL_MOD won't remove the event as far as I know. It seems the event would be triggered in the next processing loop. So why use EPOLL_CTL_MOD here rather than just EPOLL_CTL_DEL? The source code is located in `src/event/modules/ngx_epoll_module.c` static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) { // ...... if (e->active) { op = EPOLL_CTL_MOD; ee.events = prev | (uint32_t) flags; ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); } else { op = EPOLL_CTL_DEL; ee.events = 0; ee.data.ptr = NULL; } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, "epoll del event: fd:%d op:%d ev:%08XD", c->fd, op, ee.events); if (epoll_ctl(ep, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "epoll_ctl(%d, %d) failed", op, c->fd); return NGX_ERROR; } ev->active = 0; return NGX_OK; } -------------- next part -------------- An HTML attachment was scrubbed... URL: From qiyingwangwqy at gmail.com Mon Oct 28 07:51:43 2019 From: qiyingwangwqy at gmail.com (Qiying Wang) Date: Mon, 28 Oct 2019 15:51:43 +0800 Subject: Why does ngx_epoll_del_event use EPOLL_CTL_MOD Message-ID: Sorry for bothering you. I think I've made it clear. Because there's another function ngx_epoll_add_connection which add an event combined with EPOLLIN & EPOLLOUT. If using ngx_epoll_del_event on this kind of event it cannot just use EPOLL_CTL_DEL, in which way both the read and write will be delete. That's why the EPOLL_CTL_MOD was used here. There's another piece of code in the ignored parts of the code I previously quoted. Which means when deleting a read event, set it to write event and modify it, while when deleting a write event, set it to read event and modify it. if (event == NGX_READ_EVENT) { e = c->write; prev = EPOLLOUT; } else { e = c->read; prev = EPOLLIN|EPOLLRDHUP; } -------------- next part -------------- An HTML attachment was scrubbed... URL: From zchao1995 at gmail.com Mon Oct 28 07:54:31 2019 From: zchao1995 at gmail.com (Zhang Chao) Date: Mon, 28 Oct 2019 00:54:31 -0700 Subject: Why does ngx_epoll_del_event use EPOLL_CTL_MOD In-Reply-To: References: Message-ID: Hello! Sometimes You may just want to delete a single event, for instance, You just want to delete the read event but reserve the write event for a specified fd, in such case EPOLL_CTL_MOD should be used. -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.borisov at nginx.com Mon Oct 28 13:11:03 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 28 Oct 2019 13:11:03 +0000 Subject: [njs] Added njs_lvalue_arg() macro. Message-ID: details: https://hg.nginx.org/njs/rev/c43ebb4722fc branches: changeset: 1203:c43ebb4722fc user: Alexander Borisov date: Mon Oct 28 16:10:17 2019 +0300 description: Added njs_lvalue_arg() macro. diffstat: src/njs.h | 5 +++- src/njs_json.c | 15 ++++--------- src/njs_object.c | 15 ++++--------- src/njs_regexp.c | 30 +++++++++------------------ src/njs_string.c | 59 ++++++++++++++++++------------------------------------- 5 files changed, 43 insertions(+), 81 deletions(-) diffs (274 lines): diff -r 7e7d0dac4572 -r c43ebb4722fc src/njs.h --- a/src/njs.h Fri Oct 25 16:20:37 2019 +0300 +++ b/src/njs.h Mon Oct 28 16:10:17 2019 +0300 @@ -51,10 +51,13 @@ extern const njs_value_t njs_ : (njs_value_t *) &njs_value_undefined) #define njs_value_assign(dst, src) \ - *((njs_opaque_value_t *) dst) = *((njs_opaque_value_t *) src); + *((njs_opaque_value_t *) dst) = *((njs_opaque_value_t *) src) #define njs_value_arg(val) ((njs_value_t *) val) +#define njs_lvalue_arg(lvalue, args, nargs, n) \ + ((n < nargs) ? njs_argument(args, n) \ + : (njs_value_assign(lvalue, &njs_value_undefined), lvalue)) #define njs_vm_error(vm, fmt, ...) \ njs_vm_value_error_set(vm, njs_vm_retval(vm), fmt, ##__VA_ARGS__) diff -r 7e7d0dac4572 -r c43ebb4722fc src/njs_json.c --- a/src/njs_json.c Fri Oct 25 16:20:37 2019 +0300 +++ b/src/njs_json.c Mon Oct 28 16:10:17 2019 +0300 @@ -147,7 +147,7 @@ njs_json_parse(njs_vm_t *vm, njs_value_t njs_index_t unused) { njs_int_t ret; - njs_value_t *text, *value, *wrapper; + njs_value_t *text, *value, *wrapper, lvalue; const u_char *p, *end; njs_json_parse_t *parse, json_parse; const njs_value_t *reviver; @@ -162,17 +162,12 @@ njs_json_parse(njs_vm_t *vm, njs_value_t return NJS_ERROR; } - text = njs_arg(args, nargs, 1); + text = njs_lvalue_arg(&lvalue, args, nargs, 1); if (njs_slow_path(!njs_is_string(text))) { - if (njs_is_undefined(text)) { - text = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, text, text); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, text, text); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } diff -r 7e7d0dac4572 -r c43ebb4722fc src/njs_object.c --- a/src/njs_object.c Fri Oct 25 16:20:37 2019 +0300 +++ b/src/njs_object.c Mon Oct 28 16:10:17 2019 +0300 @@ -1089,7 +1089,7 @@ njs_object_define_property(njs_vm_t *vm, njs_index_t unused) { njs_int_t ret; - njs_value_t *value, *name, *desc; + njs_value_t *value, *name, *desc, lvalue; if (!njs_is_object(njs_arg(args, nargs, 1))) { njs_type_error(vm, "cannot convert %s argument to object", @@ -1111,17 +1111,12 @@ njs_object_define_property(njs_vm_t *vm, return NJS_ERROR; } - name = njs_arg(args, nargs, 2); + name = njs_lvalue_arg(&lvalue, args, nargs, 2); if (njs_slow_path(!njs_is_string(name))) { - if (njs_is_undefined(name)) { - name = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, name, name); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, name, name); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } diff -r 7e7d0dac4572 -r c43ebb4722fc src/njs_regexp.c --- a/src/njs_regexp.c Fri Oct 25 16:20:37 2019 +0300 +++ b/src/njs_regexp.c Mon Oct 28 16:10:17 2019 +0300 @@ -845,7 +845,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, njs_int_t ret; njs_uint_t n; njs_regex_t *regex; - njs_value_t *value; + njs_value_t *value, lvalue; const njs_value_t *retval; njs_string_prop_t string; njs_regexp_pattern_t *pattern; @@ -858,17 +858,12 @@ njs_regexp_prototype_test(njs_vm_t *vm, retval = &njs_value_false; - value = njs_arg(args, nargs, 1); + value = njs_lvalue_arg(&lvalue, args, nargs, 1); if (!njs_is_string(value)) { - if (njs_is_undefined(value)) { - value = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, value, value); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } @@ -921,7 +916,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, { njs_int_t ret; njs_utf8_t utf8; - njs_value_t *value; + njs_value_t *value, lvalue; njs_regexp_t *regexp; njs_string_prop_t string; njs_regexp_utf8_t type; @@ -933,17 +928,12 @@ njs_regexp_prototype_exec(njs_vm_t *vm, return NJS_ERROR; } - value = njs_arg(args, nargs, 1); + value = njs_lvalue_arg(&lvalue, args, nargs, 1); if (!njs_is_string(value)) { - if (njs_is_undefined(value)) { - value = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, value, value); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } diff -r 7e7d0dac4572 -r c43ebb4722fc src/njs_string.c --- a/src/njs_string.c Fri Oct 25 16:20:37 2019 +0300 +++ b/src/njs_string.c Mon Oct 28 16:10:17 2019 +0300 @@ -2065,9 +2065,8 @@ njs_string_prototype_last_index_of(njs_v double pos; ssize_t index, start, length, search_length; njs_int_t ret; - njs_value_t *value; + njs_value_t *value, *search_string, lvalue; const u_char *p, *end; - const njs_value_t *search_string; njs_string_prop_t string, search; ret = njs_string_object_validate(vm, njs_arg(args, nargs, 0)); @@ -2079,18 +2078,12 @@ njs_string_prototype_last_index_of(njs_v length = njs_string_prop(&string, njs_argument(args, 0)); - search_string = njs_arg(args, nargs, 1); + search_string = njs_lvalue_arg(&lvalue, args, nargs, 1); if (njs_slow_path(!njs_is_string(search_string))) { - if (njs_is_undefined(search_string)) { - search_string = &njs_string_undefined; - - } else { - ret = njs_value_to_string(vm, njs_value_arg(search_string), - njs_value_arg(search_string)); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, search_string, search_string); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } @@ -2301,7 +2294,7 @@ njs_string_starts_or_ends_with(njs_vm_t { int64_t index, length, search_length; njs_int_t ret; - njs_value_t *value; + njs_value_t *value, lvalue; const u_char *p, *end; const njs_value_t *retval; njs_string_prop_t string, search; @@ -2313,17 +2306,12 @@ njs_string_starts_or_ends_with(njs_vm_t return ret; } - value = njs_arg(args, nargs, 1); + value = njs_lvalue_arg(&lvalue, args, nargs, 1); if (njs_slow_path(!njs_is_string(value))) { - if (njs_is_undefined(value)) { - value = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, value, value); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } @@ -3478,6 +3466,7 @@ njs_string_prototype_replace(njs_vm_t *v njs_int_t ret; njs_uint_t ncaptures; njs_value_t *this, *search, *replace; + njs_value_t search_lvalue, replace_lvalue; njs_regex_t *regex; njs_string_prop_t string; njs_string_replace_t *r, string_replace; @@ -3493,8 +3482,8 @@ njs_string_prototype_replace(njs_vm_t *v goto original; } - search = njs_arg(args, nargs, 1); - replace = njs_arg(args, nargs, 2); + search = njs_lvalue_arg(&search_lvalue, args, nargs, 1); + replace = njs_lvalue_arg(&replace_lvalue, args, nargs, 2); (void) njs_string_prop(&string, this); @@ -3530,14 +3519,9 @@ njs_string_prototype_replace(njs_vm_t *v ncaptures = 1; if (!njs_is_string(search)) { - if (njs_is_undefined(search)) { - search = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, search, search); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, search, search); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } } @@ -3559,14 +3543,9 @@ njs_string_prototype_replace(njs_vm_t *v } else { if (njs_slow_path(!njs_is_string(replace))) { - if (njs_is_undefined(replace)) { - replace = njs_value_arg(&njs_string_undefined); - - } else { - ret = njs_value_to_string(vm, replace, replace); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } + ret = njs_value_to_string(vm, replace, replace); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } } From alexander.borisov at nginx.com Mon Oct 28 13:51:16 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 28 Oct 2019 13:51:16 +0000 Subject: [njs] Added conversion of this value to object in Array.prototype functions. Message-ID: details: https://hg.nginx.org/njs/rev/3c15734aaeb8 branches: changeset: 1204:3c15734aaeb8 user: Alexander Borisov date: Mon Oct 28 16:50:20 2019 +0300 description: Added conversion of this value to object in Array.prototype functions. This closes #231 issue on GitHub. diffstat: src/njs_array.c | 159 ++++++++++++++++++++++++---------------------- src/njs_value.c | 33 +++++++++ src/njs_value.h | 1 + src/test/njs_unit_test.c | 6 +- 4 files changed, 120 insertions(+), 79 deletions(-) diffs (396 lines): diff -r c43ebb4722fc -r 3c15734aaeb8 src/njs_array.c --- a/src/njs_array.c Mon Oct 28 16:10:17 2019 +0300 +++ b/src/njs_array.c Mon Oct 28 16:50:20 2019 +0300 @@ -419,16 +419,19 @@ static njs_int_t njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int64_t start, end, length; - uint32_t object_length; - njs_int_t ret; - - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "cannot convert undefined to object"); - return NJS_ERROR; + int64_t start, end, length; + uint32_t object_length; + njs_int_t ret; + njs_value_t *value; + + value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - ret = njs_object_length(vm, njs_arg(args, nargs, 0), &object_length); + ret = njs_object_length(vm, value, &object_length); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } @@ -480,7 +483,7 @@ njs_array_prototype_slice(njs_vm_t *vm, } } - return njs_array_prototype_slice_copy(vm, &args[0], start, length); + return njs_array_prototype_slice_copy(vm, value, start, length); } @@ -601,9 +604,9 @@ njs_array_prototype_push(njs_vm_t *vm, n value = njs_arg(args, nargs, 0); length = 0; - if (njs_slow_path(njs_is_null_or_undefined(value))) { - njs_type_error(vm, "Cannot convert undefined or null to object"); - return NJS_ERROR; + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } if (njs_is_array(&args[0])) { @@ -662,9 +665,9 @@ njs_array_prototype_pop(njs_vm_t *vm, nj value = njs_arg(args, nargs, 0); - if (njs_slow_path(njs_is_null_or_undefined(value))) { - njs_type_error(vm, "Cannot convert undefined or null to object"); - return NJS_ERROR; + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } njs_set_undefined(&vm->retval); @@ -722,9 +725,9 @@ njs_array_prototype_unshift(njs_vm_t *vm length = 0; n = nargs - 1; - if (njs_slow_path(njs_is_null_or_undefined(value))) { - njs_type_error(vm, "Cannot convert undefined or null to object"); - return NJS_ERROR; + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } if (njs_is_array(value)) { @@ -863,9 +866,9 @@ njs_array_prototype_shift(njs_vm_t *vm, value = njs_arg(args, nargs, 0); length = 0; - if (njs_slow_path(njs_is_null_or_undefined(value))) { - njs_type_error(vm, "Cannot convert undefined or null to object"); - return NJS_ERROR; + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } njs_set_undefined(&vm->retval); @@ -944,17 +947,19 @@ njs_array_prototype_splice(njs_vm_t *vm, njs_value_t *value; njs_array_t *array, *deleted; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "cannot convert undefined to object"); - return NJS_ERROR; + value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } array = NULL; start = 0; delete = 0; - if (njs_is_array(&args[0])) { - array = njs_array(&args[0]); + if (njs_is_array(value)) { + array = njs_array(value); length = array->length; if (nargs > 1) { @@ -1059,17 +1064,20 @@ static njs_int_t njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + njs_int_t ret; njs_uint_t i, n, length; - njs_value_t value; + njs_value_t value, *this; njs_array_t *array; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "cannot convert undefined to object"); - return NJS_ERROR; + this = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, this); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - if (njs_is_array(&args[0])) { - array = njs_array(&args[0]); + if (njs_is_array(this)) { + array = njs_array(this); length = array->length; if (length > 1) { @@ -1084,7 +1092,7 @@ njs_array_prototype_reverse(njs_vm_t *vm } else { /* STUB */ - vm->retval = args[0]; + vm->retval = *this; } return NJS_OK; @@ -1131,9 +1139,9 @@ njs_array_prototype_join(njs_vm_t *vm, n njs_value_t *value, *values; njs_string_prop_t separator, string; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "cannot convert undefined to object"); - return NJS_ERROR; + ret = njs_value_to_object(vm, &args[0]); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } if (nargs > 1 && !njs_is_string(&args[1])) { @@ -1672,10 +1680,16 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_index_t unused) { uint64_t length; + njs_int_t ret; njs_uint_t i; njs_value_t *value; njs_array_t *array; + ret = njs_value_to_object(vm, &args[0]); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + length = 0; for (i = 0; i < nargs; i++) { @@ -1749,12 +1763,13 @@ njs_array_prototype_index_of(njs_vm_t *v njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + iargs.value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs.value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs.value = njs_argument(args, 0); iargs.argument = njs_arg(args, nargs, 1); ret = njs_value_length(vm, iargs.value, &length); @@ -1804,12 +1819,13 @@ njs_array_prototype_last_index_of(njs_vm njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + iargs.value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs.value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs.value = njs_argument(args, 0); iargs.argument = njs_arg(args, nargs, 1); ret = njs_value_length(vm, iargs.value, &length); @@ -1895,12 +1911,13 @@ njs_array_prototype_includes(njs_vm_t *v njs_int_t ret; njs_array_iterator_args_t iargs; - if (njs_slow_path(njs_is_null_or_undefined(njs_arg(args, nargs, 0)))) { - njs_type_error(vm, "unexpected iterator arguments"); - return NJS_ERROR; + iargs.value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs.value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs.value = njs_argument(args, 0); iargs.argument = njs_arg(args, nargs, 1); ret = njs_value_length(vm, iargs.value, &length); @@ -1958,25 +1975,12 @@ njs_array_prototype_fill(njs_vm_t *vm, n njs_int_t i, ret; njs_array_t *array; njs_value_t name, *this, *value; - njs_object_t *object; this = njs_arg(args, nargs, 0); - if (njs_is_primitive(this)) { - if (njs_is_null_or_undefined(this)) { - njs_type_error(vm, "\"this\" argument cannot be " - "undefined or null value"); - return NJS_ERROR; - } - - object = njs_object_value_alloc(vm, this, this->type); - if (njs_slow_path(object == NULL)) { - return NJS_ERROR; - } - - njs_set_type_object(&vm->retval, object, object->type); - - return NJS_OK; + ret = njs_value_to_object(vm, this); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } array = NULL; @@ -2063,12 +2067,13 @@ njs_array_validate_args(njs_vm_t *vm, nj { njs_int_t ret; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { - goto failed; + iargs->value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs->value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs->value = njs_argument(args, 0); - ret = njs_value_length(vm, iargs->value, &iargs->to); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -2422,12 +2427,13 @@ njs_array_prototype_map(njs_vm_t *vm, nj njs_array_t *array; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { - goto unexpected_args; + iargs.value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs.value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs.value = njs_argument(args, 0); - ret = njs_value_length(vm, iargs.value, &length); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -2567,12 +2573,13 @@ njs_array_prototype_reduce_right(njs_vm_ njs_value_t accumulator; njs_array_iterator_args_t iargs; - if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) { - goto unexpected_args; + iargs.value = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, iargs.value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - iargs.value = njs_argument(args, 0); - ret = njs_value_length(vm, iargs.value, &iargs.from); if (njs_slow_path(ret != NJS_OK)) { return ret; diff -r c43ebb4722fc -r 3c15734aaeb8 src/njs_value.c --- a/src/njs_value.c Mon Oct 28 16:10:17 2019 +0300 +++ b/src/njs_value.c Mon Oct 28 16:50:20 2019 +0300 @@ -1171,3 +1171,36 @@ njs_value_property_delete(njs_vm_t *vm, return NJS_OK; } + + +njs_int_t +njs_value_to_object(njs_vm_t *vm, njs_value_t *value) +{ + njs_object_t *object; + + if (njs_slow_path(njs_is_null_or_undefined(value))) { + njs_type_error(vm, "cannot convert null or undefined to object"); + return NJS_ERROR; + } + + if (njs_is_object(value)) { + return NJS_OK; + + } + + if (njs_is_primitive(value)) { + object = njs_object_value_alloc(vm, value, value->type); + if (njs_slow_path(object == NULL)) { + return NJS_ERROR; + } + + njs_set_type_object(value, object, njs_object_value_type(value->type)); + + return NJS_OK; + } + + njs_type_error(vm, "cannot convert %s to object", + njs_type_string(value->type)); + + return NJS_ERROR; +} diff -r c43ebb4722fc -r 3c15734aaeb8 src/njs_value.h --- a/src/njs_value.h Mon Oct 28 16:10:17 2019 +0300 +++ b/src/njs_value.h Mon Oct 28 16:50:20 2019 +0300 @@ -837,6 +837,7 @@ njs_int_t njs_value_property_set(njs_vm_ njs_value_t *key, njs_value_t *setval); njs_int_t njs_value_property_delete(njs_vm_t *vm, njs_value_t *value, njs_value_t *key, njs_value_t *removed); +njs_int_t njs_value_to_object(njs_vm_t *vm, njs_value_t *value); #include "njs_number.h" diff -r c43ebb4722fc -r 3c15734aaeb8 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Oct 28 16:10:17 2019 +0300 +++ b/src/test/njs_unit_test.c Mon Oct 28 16:50:20 2019 +0300 @@ -4026,7 +4026,7 @@ static njs_unit_test_t njs_test[] = njs_str("") }, { njs_str("Array.prototype.slice.call(undefined)"), - njs_str("TypeError: cannot convert undefined to object") }, + njs_str("TypeError: cannot convert null or undefined to object") }, { njs_str("Array.prototype.slice.call(1)"), njs_str("") }, @@ -7741,10 +7741,10 @@ static njs_unit_test_t njs_test[] = njs_str("1552553") }, { njs_str("[].join.call()"), - njs_str("TypeError: cannot convert undefined to object") }, + njs_str("TypeError: cannot convert null or undefined to object") }, { njs_str("[].slice.call()"), - njs_str("TypeError: cannot convert undefined to object") }, + njs_str("TypeError: cannot convert null or undefined to object") }, { njs_str("function f(a) {} ; var a = f; var b = f; a === b"), njs_str("true") }, From guillaume-nginx at outters.eu Mon Oct 28 23:51:42 2019 From: guillaume-nginx at outters.eu (Guillaume Outters) Date: Tue, 29 Oct 2019 00:51:42 +0100 Subject: [PATCH] {{x}} syntax for configuration-time replacements Message-ID: <3f5df681b7518aa8c8e08646af8ad09f@outters.eu> Hello, following my early september attemps to introduce config-time resolved paths, and your (Maxim) thoughts that my solution introduced unclearness, I have come up with what I hope to be a better solution. In essence, this introduces a {{ ? }} syntax for config-time replacements. === Basic use case === For now I only implemented {{.}} to resolve to "directory of the currently parsed config file", and only for the 'include' directive. But this already allows "config snippets" reusability, bringing a simple solution to app-embedded nginx configuration snippets, e.g. given one nginx.conf seen by "include /var/www/whereever/you/have/put/your/*/nginx.conf;": ---------------- server { server_name appv1.local; include "{{.}}/php-fpm.conf"; } server { server_name appv2.local; include "{{.}}/php-fpm.conf"; } ---------------- we can simply have a php-fpm.conf deployed next to the app's nginx.conf, without having to go for one of the three current approaches: a. "hard-resolving" the full path at deploy time, resulting in nginx.conf containing: include /var/www/whereever/you/have/put/your/app/php-fpm.conf; (hard to read, and error prone if wanting to hand-correct some entries) b. pushing the php-fpm.conf to the configuration root, to include it from the app's nginx.conf as simply "php-fpm.conf". But then applications do not control anymore their snippets, they must adhere to the config root's version. c. ? or replace each include by the whole contents of the snippet. === Delimiter === Now for the drawback: I am not that fond of the {{ ? }} delimiter. And it maybe the best time to choose a better alternative. I think we should stick to , as opposed to : - because a two-characters prefix has more chances to collide with an existing configuration file, than a 2+2 chars frame - and because this visually distinguishes the "define-replaced" from the "runtime-replaced" variables (just imagine a world where ${var} meant runtime-replace var, when $[var] meant config-time replacement) In the 2+2 characters frame, here were candidates: directive {{.}}/php-fpm.{{php_version}}.conf; directive $$.$$/php-fpm.$$php_version$$.conf; directive ##.##/php-fpm.##php_version##.conf; directive ``.``/php-fpm.``php_version``.conf; directive ::.::/php-fpm.::php_version::.conf; directive %%.%%/php-fpm.%%php_version%%.conf; Other pairs too much looked like http URIs or other special characters. The big problem with {{ ? }} is that is FORCES to use quotes, or the '{' will be seen as a block opening. Its big advantage is that, as its opening and closing marks differ, it is easier to read {{.}}/{{type}}.{{version}}.conf than ##.##/##type##.##version##.conf Other than that, % is an interesting alternative, as long as in testing we don't name our variables from any of the 5 or 6 replacements that the testing framework harcodes. === Plans === Even with these, the solution seems far more generic than the 'nearby' I originally proposed, and whose shortnesses were easily pointed out. Plans are now to rely on this syntax to add block-scoped 'define's: ---------------- # Define default PHP version define php_version 7.3; server { server_name appv1.local; include "{{.}}/php-fpm.conf"; } server { server_name appv2.local; include "{{.}}/php-fpm.conf"; } server { server_name oldapp.local; define php_version 5.6; include "{{.}}/php-fpm.conf"; } ---------------- with php-fpm.conf containing: ---------------- ? fastcgi_pass "unix:/var/run/php{{php_version}}-fpm.sock"; ? ---------------- Note that resolution is simply done at reading time, so: include "php{{php_version}}.conf"; # Will error define php_version 7.3; include "php{{php_version}}.conf"; # Will include php7.3.conf, relative to conf root define php_version 5.6; include "php{{php_version}}.conf"; # Will include php5.6.conf === Contents of the patches === Attached patches are: 1. definition of a new ngx_conf_complex_value() function (2 added files: core/ngx_conf_def.h and core/ngx_conf_def.c) This is the core of the replacer, *without* its plugging (that is, patch 1. without patches 2. and 3. is only dead code). It includes {{.}}. 2. plugging of 1. into 'include' directive. 3. plugging of 1. into ngx_http_compile_complex_value This works on an opt-in basis, with a new attribute, ccv->compile_defs, that is 0 by default === What's next? === TODO is: - first of all, vote for a syntax! - set compile_defs = 1 on elected ngx_http_compile_complex_value callers (or even make it the default, inverting the logic to "resolve {{ ? }}s unless compile_no_defs is 1") - define 'define' keyword, and mechanism for ngx_conf_complex_value() to resolve them - document (configuration and API), test === Why not http script? === I originally thought of adding my code into ngx_http_compile_complex_value to mutualize parsing and benefit of the powerful variables resolution, but: - it created a dependency from core to http - and anyway, {{ }} resolution has to pass before http scripts parsing, so that {{ }} resolved string can contain $ or pass through config_prefix. -- Guillaume # HG changeset patch # User Guillaume Outters # Date 1572243857 -3600 # Mon Oct 28 07:24:17 2019 +0100 # Node ID 8bb356ca5a127afa4c21b57de1df950c6e059595 # Parent 89adf49fe76ada86d84e2af8f5cee9ca8c3dca19 ngx_conf_def.c: add {{ ? }} syntax for configuration-time resolved variable definitions diff -r 89adf49fe76a -r 8bb356ca5a12 auto/sources --- a/auto/sources Mon Oct 21 20:22:30 2019 +0300 +++ b/auto/sources Mon Oct 28 07:24:17 2019 +0100 @@ -36,6 +36,7 @@ src/core/ngx_connection.h \ src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ + src/core/ngx_conf_def.h \ src/core/ngx_module.h \ src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h \ @@ -73,6 +74,7 @@ src/core/ngx_rwlock.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ + src/core/ngx_conf_def.c \ src/core/ngx_module.c \ src/core/ngx_resolver.c \ src/core/ngx_open_file_cache.c \ diff -r 89adf49fe76a -r 8bb356ca5a12 src/core/ngx_conf_def.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/ngx_conf_def.c Mon Oct 28 07:24:17 2019 +0100 @@ -0,0 +1,298 @@ + +/* + * Copyright (C) Guillaume Outters + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_CONF_SCRIPT_DELIM_LEN 2 + +#define NGX_CONF_TYPE_TEXT 0 +#define NGX_CONF_TYPE_EXPR 1 + + +/* TODO: mutualize with ngx_http_script for parsing / running the mix of + * strings and variables. */ + +typedef struct { + ngx_str_t *value; + ngx_conf_t *cf; + ngx_array_t parts; + ngx_array_t part_types; +} ngx_conf_ccv_t; + +int ngx_conf_ccv_compile(ngx_conf_ccv_t *ccv); +int ngx_conf_ccv_init(ngx_conf_ccv_t *ccv, ngx_conf_t *cf, ngx_str_t *value, + ngx_uint_t n); +int ngx_conf_ccv_run(ngx_conf_ccv_t *ccv); +int ngx_conf_ccv_resolve_expr(ngx_conf_ccv_t *ccv, ngx_str_t *expr); +void ngx_conf_ccv_destroy(ngx_conf_ccv_t *ccv); + + +int +ngx_conf_complex_value(ngx_conf_t *cf, ngx_str_t *string) +{ + ngx_uint_t i, nv; + ngx_conf_ccv_t ccv; + + nv = 0; + + for (i = 0; i < string->len - 1; ++i) { + if (string->data[i] == '{' && string->data[i + 1] == '{') { + ++nv; + } + } + + if (nv == 0) { + return NGX_OK; + } + + if (ngx_conf_ccv_init(&ccv, cf, string, 2 * nv + 1) != NGX_OK) { + goto e_ccv; + } + + if (ngx_conf_ccv_compile(&ccv) != NGX_OK) { + goto e_compile; + } + + if (ngx_conf_ccv_run(&ccv) != NGX_OK) { + goto e_run; + } + + ngx_conf_ccv_destroy(&ccv); + + return NGX_OK; + +e_run: +e_compile: + ngx_conf_ccv_destroy(&ccv); +e_ccv: + return NGX_ERROR; +} + + +int +ngx_conf_ccv_init(ngx_conf_ccv_t *ccv, ngx_conf_t *cf, ngx_str_t *value, + ngx_uint_t n) +{ + ccv->value = value; + ccv->cf = cf; + + if (ngx_array_init(&ccv->parts, cf->pool, n, sizeof(ngx_str_t)) != NGX_OK) { + goto e_alloc_parts; + } + if (ngx_array_init(&ccv->part_types, cf->pool, n, sizeof(ngx_uint_t)) + != NGX_OK) + { + goto e_alloc_part_types; + } + + return NGX_OK; + + ngx_array_destroy(&ccv->part_types); +e_alloc_part_types: + ngx_array_destroy(&ccv->parts); +e_alloc_parts: + return NGX_ERROR; +} + + +void +ngx_conf_ccv_destroy(ngx_conf_ccv_t *ccv) +{ + ngx_array_destroy(&ccv->parts); + ngx_array_destroy(&ccv->part_types); +} + + +int +ngx_conf_ccv_compile(ngx_conf_ccv_t *ccv) +{ + ngx_uint_t i, current_part_start, current_part_end; + ngx_uint_t current_part_type; + + ccv->parts.nelts = 0; + ccv->part_types.nelts = 0; + current_part_type = NGX_CONF_TYPE_TEXT; + + for (current_part_start = 0; current_part_start < ccv->value->len; + /* void */ ) + { + switch (current_part_type) { + + case NGX_CONF_TYPE_TEXT: + + for (i = current_part_start; + i < ccv->value->len + && (ccv->value->data[i] != '{' || ccv->value->data[i + 1] != '{'); + /* void */ ) + { + ++i; + } + + if (i > current_part_start) { + ((ngx_str_t *) ccv->parts.elts)[ccv->parts.nelts].data = + &ccv->value->data[current_part_start]; + ((ngx_str_t *) ccv->parts.elts)[ccv->parts.nelts].len = + i - current_part_start; + ++ccv->parts.nelts; + ((ngx_uint_t *) ccv->part_types.elts)[ccv->part_types.nelts] = + current_part_type; + ++ccv->part_types.nelts; + } + if (i < ccv->value->len) { + current_part_type = NGX_CONF_TYPE_EXPR; + } + current_part_start = i; + + break; + + case NGX_CONF_TYPE_EXPR: + + for (i = current_part_start + NGX_CONF_SCRIPT_DELIM_LEN; + i < ccv->value->len - 1; ++i) + { + if (ccv->value->data[i] == '}') { + if (ccv->value->data[i + 1] == '}') { + break; + } else { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, + "forbidden \"}\" in \"%V\" at character %d", + ccv->value, current_part_start + 1); + goto e_script_parse; + } + } else if (ccv->value->data[i] == '{') { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, + "forbidden character \"%c\" in \"%V\"" + " at character %d", + ccv->value, current_part_start + 1); + goto e_script_parse; + } + } + if (i >= ccv->value->len - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, + "unbalanced {{ in \"%V\" at character %d", + ccv->value, current_part_start + 1); + goto e_script_parse; + } + + current_part_start += NGX_CONF_SCRIPT_DELIM_LEN; + while (current_part_start < ccv->value->len + && ccv->value->data[current_part_start] == ' ') + { + ++current_part_start; + } + for (current_part_end = i; + current_part_end > current_part_start + && ccv->value->data[current_part_end - 1] == ' '; + --current_part_end) + { + /* void */ + } + + if (current_part_end <= current_part_start) { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, + "invalid variable name in \"%V\" at character %d", + ccv->value, current_part_start + 1); + goto e_script_parse; + } + + ((ngx_str_t *) ccv->parts.elts)[ccv->parts.nelts].data = + &ccv->value->data[current_part_start]; + ((ngx_str_t *) ccv->parts.elts)[ccv->parts.nelts].len = + current_part_end - current_part_start; + ++ccv->parts.nelts; + ((ngx_uint_t *) ccv->part_types.elts)[ccv->part_types.nelts] = + current_part_type; + ++ccv->part_types.nelts; + + current_part_start = i + NGX_CONF_SCRIPT_DELIM_LEN; + current_part_type = NGX_CONF_TYPE_TEXT; + + break; + } + } + + return NGX_OK; + +e_script_parse: + + return NGX_ERROR; +} + + +int +ngx_conf_ccv_run(ngx_conf_ccv_t *ccv) +{ + ngx_uint_t i; + ngx_str_t *val; + size_t len; + unsigned char *ptr; + + len = 0; + + for (i = 0; i < ccv->part_types.nelts; ++i) { + switch (((ngx_uint_t *) ccv->part_types.elts)[i]) { + + case NGX_CONF_TYPE_TEXT: + val = &((ngx_str_t *) ccv->parts.elts)[i]; + len += val->len; + break; + + case NGX_CONF_TYPE_EXPR: + val = &(((ngx_str_t *) ccv->parts.elts)[i]); + if (ngx_conf_ccv_resolve_expr(ccv, val) != NGX_OK) { + return NGX_ERROR; + } + len += val->len; + break; + } + } + + ptr = ngx_pnalloc(ccv->cf->pool, len); + if (ptr == NULL) { + return NGX_ERROR; + } + + ccv->value->len = len; + ccv->value->data = ptr; + + for (i = 0; i < ccv->part_types.nelts; ++i) { + switch (((ngx_uint_t *) ccv->part_types.elts)[i]) { + + case NGX_CONF_TYPE_TEXT: + case NGX_CONF_TYPE_EXPR: + val = &((ngx_str_t *) ccv->parts.elts)[i]; + ptr = ngx_copy(ptr, val->data, val->len); + break; + } + } + + return NGX_OK; +} + + +int +ngx_conf_ccv_resolve_expr(ngx_conf_ccv_t *ccv, ngx_str_t *expr) +{ + if (expr->len == 1 && ngx_strncmp(expr->data, ".", 1) == 0) { + expr->len = ccv->cf->conf_file->file.name.len; + expr->data = ccv->cf->conf_file->file.name.data; + for (expr->len = ccv->cf->conf_file->file.name.len; + expr->data[--expr->len] != '/'; + /* void */ ) + { /* void */ } + return NGX_OK; + } else { + /* TODO: find the value of the last "define" of this context for this + * variable name. */ + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, + "not implemented: cannot resolve {{ %V }}", expr); + return NGX_ERROR; + } +} diff -r 89adf49fe76a -r 8bb356ca5a12 src/core/ngx_conf_def.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/ngx_conf_def.h Mon Oct 28 07:24:17 2019 +0100 @@ -0,0 +1,18 @@ + +/* + * Copyright (C) Guillaume Outters + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_CONF_DEF_H_INCLUDED_ +#define _NGX_CONF_DEF_H_INCLUDED_ + + +#include + + +int ngx_conf_complex_value(ngx_conf_t *cf, ngx_str_t *string); + + +#endif /* _NGX_CONF_DEF_H_INCLUDED_ */ # HG changeset patch # User Guillaume Outters # Date 1572243926 -3600 # Mon Oct 28 07:25:26 2019 +0100 # Node ID cac499a2b296d34a4f7a7a861b860e8726fd0db7 # Parent 8bb356ca5a127afa4c21b57de1df950c6e059595 include: allow {{.}} to reference current file's directory diff -r 8bb356ca5a12 -r cac499a2b296 src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c Mon Oct 28 07:24:17 2019 +0100 +++ b/src/core/ngx_conf_file.c Mon Oct 28 07:25:26 2019 +0100 @@ -7,6 +7,7 @@ #include #include +#include #define NGX_CONF_BUFFER 4096 @@ -830,6 +831,9 @@ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + if (ngx_conf_complex_value(cf, &file) != NGX_OK) { + return NGX_CONF_ERROR; + } if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } # HG changeset patch # User Guillaume Outters # Date 1572244106 -3600 # Mon Oct 28 07:28:26 2019 +0100 # Node ID ca9d5059523d8630c63867db885cd231ca93173a # Parent cac499a2b296d34a4f7a7a861b860e8726fd0db7 Core: allow opt-in {{ . }} syntax in ngx_http_compile_complex_value()-parsed configuration diff -r cac499a2b296 -r ca9d5059523d src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c Mon Oct 28 07:25:26 2019 +0100 +++ b/src/http/ngx_http_script.c Mon Oct 28 07:28:26 2019 +0100 @@ -8,6 +8,7 @@ #include #include #include +#include static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc); @@ -145,6 +146,14 @@ v = ccv->value; + if (ccv->compile_defs) { + /* Compile definitions before looking for variables, so that a + * definition's dereference can contain a variable */ + if (ngx_conf_complex_value(ccv->cf, v) != NGX_OK) { + return NGX_ERROR; + } + } + nv = 0; nc = 0; diff -r cac499a2b296 -r ca9d5059523d src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h Mon Oct 28 07:25:26 2019 +0100 +++ b/src/http/ngx_http_script.h Mon Oct 28 07:28:26 2019 +0100 @@ -83,6 +83,7 @@ unsigned zero:1; unsigned conf_prefix:1; unsigned root_prefix:1; + unsigned compile_defs:1; } ngx_http_compile_complex_value_t; -------------- next part -------------- A non-text attachment was scrubbed... Name: bundle.hg Type: application/x-mercurial-bundle Size: 3543 bytes Desc: not available URL: From alexander.borisov at nginx.com Tue Oct 29 12:25:48 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 29 Oct 2019 12:25:48 +0000 Subject: [njs] Fixed strict aliasing warnings with old GCC versions. Message-ID: details: https://hg.nginx.org/njs/rev/fedc4ad583c8 branches: changeset: 1205:fedc4ad583c8 user: Alexander Borisov date: Tue Oct 29 15:24:58 2019 +0300 description: Fixed strict aliasing warnings with old GCC versions. diffstat: src/njs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 3c15734aaeb8 -r fedc4ad583c8 src/njs.h --- a/src/njs.h Mon Oct 28 16:50:20 2019 +0300 +++ b/src/njs.h Tue Oct 29 15:24:58 2019 +0300 @@ -51,7 +51,7 @@ extern const njs_value_t njs_ : (njs_value_t *) &njs_value_undefined) #define njs_value_assign(dst, src) \ - *((njs_opaque_value_t *) dst) = *((njs_opaque_value_t *) src) + memcpy(dst, src, sizeof(njs_opaque_value_t)) #define njs_value_arg(val) ((njs_value_t *) val) From alexander.borisov at nginx.com Wed Oct 30 13:43:43 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 30 Oct 2019 13:43:43 +0000 Subject: [njs] Fixed iterator for Array.prototype.find/findIndex() functions. Message-ID: details: https://hg.nginx.org/njs/rev/926dfdd7a34c branches: changeset: 1206:926dfdd7a34c user: Alexander Borisov date: Wed Oct 30 16:43:09 2019 +0300 description: Fixed iterator for Array.prototype.find/findIndex() functions. Array might be changed in callback function. If an array became smaller than the initial one, it is necessary to iterate the missing values as invalid. This closes #229 issue on GitHub. diffstat: src/njs_array.c | 14 ++++++++------ src/test/njs_unit_test.c | 10 ++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diffs (65 lines): diff -r fedc4ad583c8 -r 926dfdd7a34c src/njs_array.c --- a/src/njs_array.c Tue Oct 29 15:24:58 2019 +0300 +++ b/src/njs_array.c Wed Oct 30 16:43:09 2019 +0300 @@ -1380,7 +1380,7 @@ njs_array_iterator(njs_vm_t *vm, njs_arr uint32_t length, i, from, to; njs_int_t ret; njs_array_t *keys; - njs_value_t *entry, *value, character, index, string_obj; + njs_value_t *value, character, index, string_obj; njs_object_t *object; const u_char *p, *end, *pos; njs_string_prop_t string_prop; @@ -1395,9 +1395,13 @@ njs_array_iterator(njs_vm_t *vm, njs_arr } for (i = from; i < to; i++) { - entry = &njs_array_start(value)[i]; - - ret = handler(vm, args, entry, i); + if (i < njs_array_len(value)) { + ret = handler(vm, args, &njs_array_start(value)[i], i); + + } else { + ret = handler(vm, args, njs_value_arg(&njs_value_invalid), i); + } + if (njs_slow_path(ret != NJS_OK)) { if (ret > 0) { return NJS_DECLINED; @@ -1405,8 +1409,6 @@ njs_array_iterator(njs_vm_t *vm, njs_arr return NJS_ERROR; } - - to = njs_min(to, njs_array_len(value)); } return NJS_OK; diff -r fedc4ad583c8 -r 926dfdd7a34c src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Oct 29 15:24:58 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 30 16:43:09 2019 +0300 @@ -4813,6 +4813,11 @@ static njs_unit_test_t njs_test[] = "catch (e) {i += '; ' + e} i"), njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var callz = 0, res = [], arr = 'abc'.split('');" + "void arr.find((k) => { if (0 == callz++) { arr.splice(1,1); } res.push(k) });" + "res.join(',')"), + njs_str("a,c,") }, + { njs_str("var a = [];" "a.findIndex(function(v, i, a) { return v > 1 })"), njs_str("-1") }, @@ -4872,6 +4877,11 @@ static njs_unit_test_t njs_test[] = "catch (e) {i += '; ' + e} i"), njs_str("1; TypeError: unexpected iterator arguments") }, + { njs_str("var callz = 0, res = [], arr = 'abc'.split('');" + "void arr.findIndex((k) => { if (0 == callz++) { arr.splice(1,1); } res.push(k) });" + "res.join(',')"), + njs_str("a,c,") }, + { njs_str("var a = [];" "a.map(function(v, i, a) { return v + 1 })"), njs_str("") }, From alexander.borisov at nginx.com Wed Oct 30 13:43:43 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 30 Oct 2019 13:43:43 +0000 Subject: [njs] Fixed Array.prototype.includes() with "undefined" argument. Message-ID: details: https://hg.nginx.org/njs/rev/2f21b596ce15 branches: changeset: 1207:2f21b596ce15 user: Alexander Borisov date: Wed Oct 30 16:43:10 2019 +0300 description: Fixed Array.prototype.includes() with "undefined" argument. This closes #230 issue on GitHub. diffstat: src/njs_array.c | 6 +++++- src/test/njs_unit_test.c | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diffs (36 lines): diff -r 926dfdd7a34c -r 2f21b596ce15 src/njs_array.c --- a/src/njs_array.c Wed Oct 30 16:43:09 2019 +0300 +++ b/src/njs_array.c Wed Oct 30 16:43:10 2019 +0300 @@ -1880,6 +1880,10 @@ static njs_int_t njs_array_handler_includes(njs_vm_t *vm, njs_array_iterator_args_t *args, njs_value_t *entry, uint32_t n) { + if (!njs_is_valid(entry)) { + entry = njs_value_arg(&njs_value_undefined); + } + if (njs_values_strict_equal(args->argument, entry)) { njs_set_true(&vm->retval); @@ -1947,7 +1951,7 @@ njs_array_prototype_includes(njs_vm_t *v iargs.from = (uint32_t) from; iargs.to = length; - if (njs_is_numeric(iargs.argument) && isnan(njs_number(iargs.argument))) { + if (njs_is_number(iargs.argument) && isnan(njs_number(iargs.argument))) { ret = njs_array_iterator(vm, &iargs, njs_array_handler_includes_nan); if (njs_fast_path(ret == NJS_DECLINED)) { return NJS_OK; diff -r 926dfdd7a34c -r 2f21b596ce15 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 30 16:43:09 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 30 16:43:10 2019 +0300 @@ -6202,6 +6202,9 @@ static njs_unit_test_t njs_test[] = "Array.prototype.includes.call(o); i"), njs_str("1") }, + { njs_str("[,,,].includes(undefined)"), + njs_str("true") }, + { njs_str("''.startsWith('')"), njs_str("true") }, From alexander.borisov at nginx.com Wed Oct 30 13:43:44 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 30 Oct 2019 13:43:44 +0000 Subject: [njs] Fixed Array.prototype.join() with "undefined" argument. Message-ID: details: https://hg.nginx.org/njs/rev/758bbc9f105a branches: changeset: 1208:758bbc9f105a user: Alexander Borisov date: Wed Oct 30 16:43:12 2019 +0300 description: Fixed Array.prototype.join() with "undefined" argument. This closes #232 issue on GitHub. diffstat: src/njs_array.c | 26 +++++++++++++------------- src/test/njs_unit_test.c | 3 +++ 2 files changed, 16 insertions(+), 13 deletions(-) diffs (59 lines): diff -r 2f21b596ce15 -r 758bbc9f105a src/njs_array.c --- a/src/njs_array.c Wed Oct 30 16:43:10 2019 +0300 +++ b/src/njs_array.c Wed Oct 30 16:43:12 2019 +0300 @@ -1144,13 +1144,22 @@ njs_array_prototype_join(njs_vm_t *vm, n return ret; } - if (nargs > 1 && !njs_is_string(&args[1])) { - ret = njs_value_to_string(vm, &args[1], &args[1]); - if (njs_slow_path(ret != NJS_OK)) { - return ret; + value = njs_arg(args, nargs, 1); + + if (njs_slow_path(!njs_is_string(value))) { + if (njs_is_undefined(value)) { + value = njs_value_arg(&njs_string_comma); + + } else { + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } } } + (void) njs_string_prop(&separator, value); + if (!njs_is_array(&args[0]) || njs_array_len(&args[0]) == 0) { vm->retval = njs_string_empty; return NJS_OK; @@ -1232,15 +1241,6 @@ njs_array_prototype_join(njs_vm_t *vm, n } } - if (nargs > 1) { - value = &args[1]; - - } else { - value = njs_value_arg(&njs_string_comma); - } - - (void) njs_string_prop(&separator, value); - size += separator.size * (array->length - 1); length += separator.length * (array->length - 1); diff -r 2f21b596ce15 -r 758bbc9f105a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Oct 30 16:43:10 2019 +0300 +++ b/src/test/njs_unit_test.c Wed Oct 30 16:43:12 2019 +0300 @@ -7756,6 +7756,9 @@ static njs_unit_test_t njs_test[] = { njs_str("[].join.call()"), njs_str("TypeError: cannot convert null or undefined to object") }, + { njs_str("[1,2,3].join(undefined)"), + njs_str("1,2,3") }, + { njs_str("[].slice.call()"), njs_str("TypeError: cannot convert null or undefined to object") }, From xeioex at nginx.com Thu Oct 31 15:18:02 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:02 +0000 Subject: [njs] Extending njs_prop_handler_t prototype. Message-ID: details: https://hg.nginx.org/njs/rev/796870eab669 branches: changeset: 1209:796870eab669 user: Dmitry Volyntsev date: Thu Oct 31 18:17:30 2019 +0300 description: Extending njs_prop_handler_t prototype. diffstat: src/njs_array.c | 4 ++-- src/njs_builtin.c | 16 ++++++++-------- src/njs_error.c | 4 ++-- src/njs_function.c | 8 ++++---- src/njs_function.h | 4 ++-- src/njs_object.c | 18 +++++++++--------- src/njs_object.h | 16 +++++++++------- src/njs_object_prop.c | 5 +++-- src/njs_regexp.c | 27 ++++++++++++++------------- src/njs_string.c | 4 ++-- src/njs_value.c | 24 +++++++++++++----------- src/njs_value.h | 33 +++++++++++++++++---------------- src/njs_vmcode.c | 2 +- 13 files changed, 86 insertions(+), 79 deletions(-) diffs (462 lines): diff -r 758bbc9f105a -r 796870eab669 src/njs_array.c --- a/src/njs_array.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_array.c Thu Oct 31 18:17:30 2019 +0300 @@ -329,8 +329,8 @@ const njs_object_init_t njs_array_const static njs_int_t -njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval) +njs_array_length(njs_vm_t *vm,njs_object_prop_t *prop, njs_value_t *value, + njs_value_t *setval, njs_value_t *retval) { double num; int64_t size; diff -r 758bbc9f105a -r 796870eab669 src/njs_builtin.c --- a/src/njs_builtin.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:30 2019 +0300 @@ -1211,8 +1211,8 @@ const njs_object_init_t njs_njs_object_ static njs_int_t -njs_process_object_argv(njs_vm_t *vm, njs_value_t *process, - njs_value_t *unused, njs_value_t *retval) +njs_process_object_argv(njs_vm_t *vm, njs_object_prop_t *pr, + njs_value_t *process, njs_value_t *unused, njs_value_t *retval) { char **arg; njs_int_t ret; @@ -1324,8 +1324,8 @@ njs_env_hash_init(njs_vm_t *vm, njs_lvlh static njs_int_t -njs_process_object_env(njs_vm_t *vm, njs_value_t *process, - njs_value_t *unused, njs_value_t *retval) +njs_process_object_env(njs_vm_t *vm, njs_object_prop_t *pr, + njs_value_t *process, njs_value_t *unused, njs_value_t *retval) { njs_int_t ret; njs_object_t *env; @@ -1369,8 +1369,8 @@ njs_process_object_env(njs_vm_t *vm, njs static njs_int_t -njs_process_object_pid(njs_vm_t *vm, njs_value_t *unused, - njs_value_t *unused2, njs_value_t *retval) +njs_process_object_pid(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *unused, njs_value_t *unused2, njs_value_t *retval) { njs_set_number(retval, getpid()); @@ -1379,8 +1379,8 @@ njs_process_object_pid(njs_vm_t *vm, njs static njs_int_t -njs_process_object_ppid(njs_vm_t *vm, njs_value_t *unused, - njs_value_t *unused2, njs_value_t *retval) +njs_process_object_ppid(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *unused, njs_value_t *unused2, njs_value_t *retval) { njs_set_number(retval, getppid()); diff -r 758bbc9f105a -r 796870eab669 src/njs_error.c --- a/src/njs_error.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_error.c Thu Oct 31 18:17:30 2019 +0300 @@ -545,8 +545,8 @@ njs_memory_error_constructor(njs_vm_t *v static njs_int_t -njs_memory_error_prototype_create(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_memory_error_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { int32_t index; njs_function_t *function; diff -r 758bbc9f105a -r 796870eab669 src/njs_function.c --- a/src/njs_function.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_function.c Thu Oct 31 18:17:30 2019 +0300 @@ -681,8 +681,8 @@ njs_function_property_prototype_create(n */ njs_int_t -njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_function_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_value_t *proto, proto_value, *cons; njs_object_t *prototype; @@ -883,8 +883,8 @@ const njs_object_init_t njs_function_co * the typical number of arguments expected by the function. */ static njs_int_t -njs_function_instance_length(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_function_instance_length(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_object_t *proto; njs_function_t *function; diff -r 758bbc9f105a -r 796870eab669 src/njs_function.h --- a/src/njs_function.h Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_function.h Thu Oct 31 18:17:30 2019 +0300 @@ -105,8 +105,8 @@ njs_int_t njs_function_arguments_object_ njs_native_frame_t *frame); njs_int_t njs_function_rest_parameters_init(njs_vm_t *vm, njs_native_frame_t *frame); -njs_int_t njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +njs_int_t njs_function_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval); njs_int_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); njs_int_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, diff -r 758bbc9f105a -r 796870eab669 src/njs_object.c --- a/src/njs_object.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_object.c Thu Oct 31 18:17:30 2019 +0300 @@ -1311,7 +1311,7 @@ njs_object_get_prototype_of(njs_vm_t *vm value = njs_arg(args, nargs, 1); if (njs_is_object(value)) { - njs_object_prototype_proto(vm, value, NULL, &vm->retval); + njs_object_prototype_proto(vm, NULL, value, NULL, &vm->retval); return NJS_OK; } @@ -1563,8 +1563,8 @@ njs_object_is_extensible(njs_vm_t *vm, n */ njs_int_t -njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_uint_t index; njs_object_t *proto; @@ -1594,8 +1594,8 @@ njs_primitive_prototype_get_proto(njs_vm */ njs_int_t -njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_object_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { int32_t index; njs_function_t *function; @@ -1877,8 +1877,8 @@ njs_object_set_prototype_of(njs_vm_t *vm njs_int_t -njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_object_prototype_proto(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_int_t ret; njs_object_t *proto, *object; @@ -1924,8 +1924,8 @@ njs_object_prototype_proto(njs_vm_t *vm, */ njs_int_t -njs_object_prototype_create_constructor(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_object_prototype_create_constructor(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { int32_t index; njs_value_t *cons; diff -r 758bbc9f105a -r 796870eab669 src/njs_object.h --- a/src/njs_object.h Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_object.h Thu Oct 31 18:17:30 2019 +0300 @@ -55,16 +55,18 @@ njs_int_t njs_object_hash_create(njs_vm_ const njs_object_prop_t *prop, njs_uint_t n); njs_int_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); -njs_int_t njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +njs_int_t njs_primitive_prototype_get_proto(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); +njs_int_t njs_object_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval); njs_value_t *njs_property_prototype_create(njs_vm_t *vm, njs_lvlhsh_t *hash, njs_object_t *prototype); -njs_int_t njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +njs_int_t njs_object_prototype_proto(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval); njs_int_t njs_object_prototype_create_constructor(njs_vm_t *vm, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval); + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); njs_value_t *njs_property_constructor_create(njs_vm_t *vm, njs_lvlhsh_t *hash, njs_value_t *constructor); njs_int_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args, diff -r 758bbc9f105a -r 796870eab669 src/njs_object_prop.c --- a/src/njs_object_prop.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_object_prop.c Thu Oct 31 18:17:30 2019 +0300 @@ -338,7 +338,8 @@ done: if (njs_is_valid(&prop->value)) { if (prev->type == NJS_PROPERTY_HANDLER) { if (njs_is_data_descriptor(prev) && prev->writable) { - ret = prev->value.data.u.prop_handler(vm, object, &prop->value, + ret = prev->value.data.u.prop_handler(vm, prev, object, + &prop->value, &vm->retval); if (njs_slow_path(ret == NJS_ERROR)) { return ret; @@ -600,7 +601,7 @@ njs_object_prop_descriptor(njs_vm_t *vm, case NJS_PROPERTY_HANDLER: pq.scratch = *prop; prop = &pq.scratch; - ret = prop->value.data.u.prop_handler(vm, value, NULL, + ret = prop->value.data.u.prop_handler(vm, prop, value, NULL, &prop->value); if (njs_slow_path(ret == NJS_ERROR)) { return ret; diff -r 758bbc9f105a -r 796870eab669 src/njs_regexp.c --- a/src/njs_regexp.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_regexp.c Thu Oct 31 18:17:30 2019 +0300 @@ -19,8 +19,9 @@ static void *njs_regexp_malloc(size_t si static void njs_regexp_free(void *p, void *memory_data); static njs_regexp_flags_t njs_regexp_flags(u_char **start, u_char *end, njs_bool_t bound); -static njs_int_t njs_regexp_prototype_source(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +static njs_int_t njs_regexp_prototype_source(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); static int njs_regexp_pattern_compile(njs_vm_t *vm, njs_regex_t *regex, u_char *source, int options); static u_char *njs_regexp_compile_trace_handler(njs_trace_t *trace, @@ -126,7 +127,7 @@ njs_regexp_constructor(njs_vm_t *vm, njs re_flags = 0; if (njs_is_regexp(pattern)) { - ret = njs_regexp_prototype_source(vm, pattern, NULL, &source); + ret = njs_regexp_prototype_source(vm, NULL, pattern, NULL, &source); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -723,8 +724,8 @@ njs_regexp_alloc(njs_vm_t *vm, njs_regex static njs_int_t -njs_regexp_prototype_last_index(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_regexp_prototype_last_index(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { uint32_t index; njs_regexp_t *regexp; @@ -744,8 +745,8 @@ njs_regexp_prototype_last_index(njs_vm_t static njs_int_t -njs_regexp_prototype_global(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_regexp_prototype_global(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_regexp_pattern_t *pattern; @@ -758,8 +759,8 @@ njs_regexp_prototype_global(njs_vm_t *vm static njs_int_t -njs_regexp_prototype_ignore_case(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_regexp_prototype_ignore_case(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_regexp_pattern_t *pattern; @@ -772,8 +773,8 @@ njs_regexp_prototype_ignore_case(njs_vm_ static njs_int_t -njs_regexp_prototype_multiline(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_regexp_prototype_multiline(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_regexp_pattern_t *pattern; @@ -786,8 +787,8 @@ njs_regexp_prototype_multiline(njs_vm_t static njs_int_t -njs_regexp_prototype_source(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_regexp_prototype_source(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { u_char *source; int32_t length; diff -r 758bbc9f105a -r 796870eab669 src/njs_string.c --- a/src/njs_string.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_string.c Thu Oct 31 18:17:30 2019 +0300 @@ -637,8 +637,8 @@ const njs_object_init_t njs_string_cons static njs_int_t -njs_string_instance_length(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_string_instance_length(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { size_t size; uintptr_t length; diff -r 758bbc9f105a -r 796870eab669 src/njs_value.c --- a/src/njs_value.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_value.c Thu Oct 31 18:17:30 2019 +0300 @@ -17,10 +17,12 @@ static njs_int_t njs_string_property_que njs_property_query_t *pq, njs_value_t *object, uint32_t index); static njs_int_t njs_external_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object); -static njs_int_t njs_external_property_set(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); -static njs_int_t njs_external_property_delete(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +static njs_int_t njs_external_property_set(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); +static njs_int_t njs_external_property_delete(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); const njs_value_t njs_value_null = njs_value(NJS_NULL, 0, 0.0); @@ -870,8 +872,8 @@ done: static njs_int_t -njs_external_property_set(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval) +njs_external_property_set(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { void *obj; njs_int_t ret; @@ -899,8 +901,8 @@ njs_external_property_set(njs_vm_t *vm, static njs_int_t -njs_external_property_delete(njs_vm_t *vm, njs_value_t *value, - njs_value_t *unused, njs_value_t *unused2) +njs_external_property_delete(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *unused, njs_value_t *unused2) { void *obj; njs_property_query_t *pq; @@ -949,7 +951,7 @@ njs_value_property(njs_vm_t *vm, njs_val case NJS_PROPERTY_HANDLER: pq.scratch = *prop; prop = &pq.scratch; - ret = prop->value.data.u.prop_handler(vm, value, NULL, + ret = prop->value.data.u.prop_handler(vm, prop, value, NULL, &prop->value); if (njs_slow_path(ret == NJS_ERROR)) { @@ -1029,7 +1031,7 @@ njs_value_property_set(njs_vm_t *vm, njs } if (prop->type == NJS_PROPERTY_HANDLER) { - ret = prop->value.data.u.prop_handler(vm, value, setval, + ret = prop->value.data.u.prop_handler(vm, prop, value, setval, &vm->retval); if (njs_slow_path(ret != NJS_DECLINED)) { return ret; @@ -1134,7 +1136,7 @@ njs_value_property_delete(njs_vm_t *vm, switch (prop->type) { case NJS_PROPERTY_HANDLER: if (njs_is_external(value)) { - ret = prop->value.data.u.prop_handler(vm, value, NULL, NULL); + ret = prop->value.data.u.prop_handler(vm, prop, value, NULL, NULL); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 758bbc9f105a -r 796870eab669 src/njs_value.h --- a/src/njs_value.h Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_value.h Thu Oct 31 18:17:30 2019 +0300 @@ -69,6 +69,19 @@ typedef enum { } njs_value_type_t; +typedef struct njs_object_prop_s njs_object_prop_t; +typedef struct njs_string_s njs_string_t; +typedef struct njs_object_s njs_object_t; +typedef struct njs_object_value_s njs_object_value_t; +typedef struct njs_function_lambda_s njs_function_lambda_t; +typedef struct njs_regexp_pattern_s njs_regexp_pattern_t; +typedef struct njs_array_s njs_array_t; +typedef struct njs_regexp_s njs_regexp_t; +typedef struct njs_date_s njs_date_t; +typedef struct njs_property_next_s njs_property_next_t; +typedef struct njs_object_init_s njs_object_init_t; + + /* * njs_prop_handler_t operates as a property getter and/or setter. * The handler receives NULL setval if it is invoked in GET context and @@ -80,23 +93,11 @@ typedef enum { * NJS_DECLINED - handler was applied to inappropriate object, vm->retval * contains undefined value. */ -typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); +typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval); typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t retval); - -typedef struct njs_string_s njs_string_t; -typedef struct njs_object_s njs_object_t; -typedef struct njs_object_value_s njs_object_value_t; -typedef struct njs_function_lambda_s njs_function_lambda_t; -typedef struct njs_regexp_pattern_s njs_regexp_pattern_t; -typedef struct njs_array_s njs_array_t; -typedef struct njs_regexp_s njs_regexp_t; -typedef struct njs_date_s njs_date_t; -typedef struct njs_property_next_s njs_property_next_t; -typedef struct njs_object_init_s njs_object_init_t; - #if (!NJS_HAVE_GCC_ATTRIBUTE_ALIGNED) #error "aligned attribute is required" #endif @@ -312,7 +313,7 @@ typedef enum { } njs_object_attribute_t; -typedef struct { +struct njs_object_prop_s { /* Must be aligned to njs_value_t. */ njs_value_t value; njs_value_t name; @@ -325,7 +326,7 @@ typedef struct { njs_object_attribute_t writable:8; /* 2 bits */ njs_object_attribute_t enumerable:8; /* 2 bits */ njs_object_attribute_t configurable:8; /* 2 bits */ -} njs_object_prop_t; +}; typedef struct { diff -r 758bbc9f105a -r 796870eab669 src/njs_vmcode.c --- a/src/njs_vmcode.c Wed Oct 30 16:43:12 2019 +0300 +++ b/src/njs_vmcode.c Thu Oct 31 18:17:30 2019 +0300 @@ -1241,7 +1241,7 @@ njs_vmcode_proto_init(njs_vm_t *vm, njs_ goto fail; } - ret = prop->value.data.u.prop_handler(vm, value, init, &vm->retval); + ret = prop->value.data.u.prop_handler(vm, prop, value, init, &vm->retval); if (njs_slow_path(ret != NJS_OK)) { goto fail; } From xeioex at nginx.com Thu Oct 31 15:18:02 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:02 +0000 Subject: [njs] Moving top-level objects to global object. Message-ID: details: https://hg.nginx.org/njs/rev/ba6f17a75b3a branches: changeset: 1210:ba6f17a75b3a user: Dmitry Volyntsev date: Thu Oct 31 18:17:31 2019 +0300 description: Moving top-level objects to global object. diffstat: src/njs_builtin.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ src/njs_generator.c | 34 ----------------- src/njs_lexer.h | 9 +---- src/njs_lexer_keyword.c | 9 +---- src/njs_object_hash.h | 34 +++++++++++++++++ src/njs_parser_terminal.c | 50 -------------------------- src/njs_value.h | 15 ++++++- src/test/njs_unit_test.c | 37 +++++++++++++++++++ test/njs_expect_test.exp | 4 +- 9 files changed, 178 insertions(+), 104 deletions(-) diffs (448 lines): diff -r 796870eab669 -r ba6f17a75b3a src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 @@ -1042,8 +1042,58 @@ njs_dump_value(njs_vm_t *vm, njs_value_t } +static njs_int_t +njs_top_level_object(njs_vm_t *vm, njs_object_prop_t *self, + njs_value_t *global, njs_value_t *setval, njs_value_t *retval) +{ + njs_int_t ret; + njs_object_t *object; + njs_object_prop_t *prop; + njs_lvlhsh_query_t lhq; + + if (njs_slow_path(setval != NULL)) { + *retval = *setval; + + } else { + njs_set_object(retval, &vm->shared->objects[self->value.data.magic16]); + + object = njs_object_value_copy(vm, retval); + if (njs_slow_path(object == NULL)) { + return NJS_ERROR; + } + } + + prop = njs_object_prop_alloc(vm, &self->name, retval, 1); + if (njs_slow_path(prop == NULL)) { + return NJS_ERROR; + } + + /* GC */ + + prop->value = *retval; + prop->enumerable = 0; + + lhq.value = prop; + njs_string_get(&self->name, &lhq.key); + lhq.key_hash = self->value.data.magic32; + lhq.replace = 1; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_object_hash_proto; + + ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq); + if (njs_slow_path(ret != NJS_OK)) { + njs_internal_error(vm, "lvlhsh insert/replace failed"); + return NJS_ERROR; + } + + return NJS_OK; +} + + static const njs_object_prop_t njs_global_this_object_properties[] = { + /* Global constants. */ + { .type = NJS_PROPERTY, .name = njs_string("NaN"), @@ -1062,6 +1112,8 @@ static const njs_object_prop_t njs_glob .value = njs_value(NJS_UNDEFINED, 0, NAN), }, + /* Global functions. */ + { .type = NJS_PROPERTY, .name = njs_string("isFinite"), @@ -1174,6 +1226,44 @@ static const njs_object_prop_t njs_glob .configurable = 1, }, + /* Global objects. */ + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("njs"), + .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_NJS, + NJS_NJS_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("process"), + .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_PROCESS, + NJS_PROCESS_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Math"), + .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_MATH, + NJS_MATH_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("JSON"), + .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_JSON, + NJS_JSON_HASH), + .writable = 1, + .configurable = 1, + }, + }; diff -r 796870eab669 -r ba6f17a75b3a src/njs_generator.c --- a/src/njs_generator.c Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_generator.c Thu Oct 31 18:17:31 2019 +0300 @@ -59,8 +59,6 @@ static u_char *njs_generate_reserve(njs_ size_t size); static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); -static njs_int_t njs_generate_builtin_object(njs_vm_t *vm, - njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node, njs_reference_type_t type); static njs_int_t njs_generate_var_statement(njs_vm_t *vm, @@ -460,12 +458,6 @@ njs_generate(njs_vm_t *vm, njs_generator return NJS_OK; - case NJS_TOKEN_NJS: - case NJS_TOKEN_PROCESS: - case NJS_TOKEN_MATH: - case NJS_TOKEN_JSON: - return njs_generate_builtin_object(vm, generator, node); - case NJS_TOKEN_FUNCTION: return njs_generate_function_declaration(vm, generator, node); @@ -587,32 +579,6 @@ njs_generate_name(njs_vm_t *vm, njs_gene static njs_int_t -njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node) -{ - njs_index_t index; - njs_vmcode_object_copy_t *copy; - - index = njs_variable_index(vm, node); - if (njs_slow_path(index == NJS_INDEX_NONE)) { - return NJS_ERROR; - } - - node->index = njs_generate_dest_index(vm, generator, node); - if (njs_slow_path(node->index == NJS_INDEX_ERROR)) { - return NJS_ERROR; - } - - njs_generate_code(generator, njs_vmcode_object_copy_t, copy, - NJS_VMCODE_OBJECT_COPY, 2); - copy->retval = node->index; - copy->object = index; - - return NJS_OK; -} - - -static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node, njs_reference_type_t type) { diff -r 796870eab669 -r ba6f17a75b3a src/njs_lexer.h --- a/src/njs_lexer.h Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_lexer.h Thu Oct 31 18:17:31 2019 +0300 @@ -166,18 +166,11 @@ typedef enum { NJS_TOKEN_THROW, NJS_TOKEN_THIS, + NJS_TOKEN_GLOBAL_OBJECT, NJS_TOKEN_NON_LOCAL_THIS, NJS_TOKEN_ARGUMENTS, NJS_TOKEN_EVAL, -#define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_OBJECT - - NJS_TOKEN_GLOBAL_OBJECT, - NJS_TOKEN_NJS, - NJS_TOKEN_PROCESS, - NJS_TOKEN_MATH, - NJS_TOKEN_JSON, - NJS_TOKEN_OBJECT_CONSTRUCTOR, NJS_TOKEN_ARRAY_CONSTRUCTOR, NJS_TOKEN_BOOLEAN_CONSTRUCTOR, diff -r 796870eab669 -r ba6f17a75b3a src/njs_lexer_keyword.c --- a/src/njs_lexer_keyword.c Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_lexer_keyword.c Thu Oct 31 18:17:31 2019 +0300 @@ -47,14 +47,6 @@ static const njs_keyword_t njs_keywords { njs_str("finally"), NJS_TOKEN_FINALLY, 0 }, { njs_str("throw"), NJS_TOKEN_THROW, 0 }, - /* Builtin objects. */ - - { njs_str("this"), NJS_TOKEN_THIS, 0 }, - { njs_str("njs"), NJS_TOKEN_NJS, 0 }, - { njs_str("process"), NJS_TOKEN_PROCESS, 0 }, - { njs_str("Math"), NJS_TOKEN_MATH, 0 }, - { njs_str("JSON"), NJS_TOKEN_JSON, 0 }, - /* Builtin functions. */ { njs_str("Object"), NJS_TOKEN_OBJECT_CONSTRUCTOR, 0 }, @@ -82,6 +74,7 @@ static const njs_keyword_t njs_keywords /* Reserved words. */ + { njs_str("this"), NJS_TOKEN_THIS, 0 }, { njs_str("arguments"), NJS_TOKEN_ARGUMENTS, 0 }, { njs_str("eval"), NJS_TOKEN_EVAL, 0 }, diff -r 796870eab669 -r ba6f17a75b3a src/njs_object_hash.h --- a/src/njs_object_hash.h Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_object_hash.h Thu Oct 31 18:17:31 2019 +0300 @@ -146,6 +146,14 @@ 'j'), 'o'), 'i'), 'n') +#define NJS_JSON_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'J'), 'S'), 'O'), 'N') + + #define NJS_LENGTH_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -164,6 +172,21 @@ 'n'), 'a'), 'm'), 'e') +#define NJS_NJS_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'n'), 'j'), 's') + + +#define NJS_MATH_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'M'), 'a'), 't'), 'h') + + #define NJS_MESSAGE_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -202,6 +225,17 @@ 'p'), 'a'), 't'), 'h') +#define NJS_PROCESS_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'p'), 'r'), 'o'), 'c'), 'e'), 's'), 's') + + #define NJS_PROTOTYPE_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ diff -r 796870eab669 -r ba6f17a75b3a src/njs_parser_terminal.c --- a/src/njs_parser_terminal.c Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_parser_terminal.c Thu Oct 31 18:17:31 2019 +0300 @@ -11,9 +11,6 @@ static njs_parser_node_t *njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, njs_str_t *name, uint32_t hash, uint32_t token_line); -static njs_int_t njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, - njs_parser_node_t *node, njs_value_type_t type, njs_str_t *name, - uint32_t hash); static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj); static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser, @@ -259,17 +256,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p break; - case NJS_TOKEN_NJS: - case NJS_TOKEN_PROCESS: - case NJS_TOKEN_MATH: - case NJS_TOKEN_JSON: - ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - - break; - case NJS_TOKEN_OBJECT_CONSTRUCTOR: node->index = NJS_INDEX_OBJECT; break; @@ -399,42 +385,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p } -static njs_int_t -njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node, - njs_value_type_t type, njs_str_t *name, uint32_t hash) -{ - njs_int_t ret; - njs_uint_t index; - njs_variable_t *var; - njs_parser_scope_t *scope; - - scope = njs_parser_global_scope(vm); - - var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR); - if (njs_slow_path(var == NULL)) { - return NJS_ERROR; - } - - /* TODO: once */ - switch (type) { - case NJS_OBJECT: - index = node->token - NJS_TOKEN_FIRST_OBJECT; - njs_set_object(&var->value, &vm->shared->objects[index]); - break; - - default: - return NJS_ERROR; - } - - ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - return NJS_OK; -} - - static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) { diff -r 796870eab669 -r ba6f17a75b3a src/njs_value.h --- a/src/njs_value.h Thu Oct 31 18:17:30 2019 +0300 +++ b/src/njs_value.h Thu Oct 31 18:17:31 2019 +0300 @@ -128,8 +128,8 @@ union njs_value_s { */ uint8_t truth; - uint16_t _spare1; - uint32_t _spare2; + uint16_t magic16; + uint32_t magic32; union { double number; @@ -409,6 +409,17 @@ typedef struct { } +#define njs_prop_handler2(_handler, _magic16, _magic32) { \ + .data = { \ + .type = NJS_INVALID, \ + .truth = 1, \ + .magic16 = _magic16, \ + .magic32 = _magic32, \ + .u = { .prop_handler = _handler } \ + } \ +} + + #define njs_is_null(value) \ ((value)->type == NJS_NULL) diff -r 796870eab669 -r ba6f17a75b3a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 31 18:17:30 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 31 18:17:31 2019 +0300 @@ -13227,6 +13227,43 @@ static njs_unit_test_t njs_test[] = { njs_str("parseFloat('-5.7e+abc')"), njs_str("-5.7") }, + /* Top-level objects. */ + + { njs_str("var global = this;" + "function isMutableObject(v) {" + " var d = Object.getOwnPropertyDescriptor(global, v);" + " return d.writable && !d.enumerable && d.configurable;" + "};" + "['njs', 'process', 'Math', 'JSON'].every((v)=>isMutableObject(v))"), + njs_str("true") }, + + { njs_str("njs === njs"), + njs_str("true") }, + + { njs_str("this.njs = 1; njs"), + njs_str("1") }, + + { njs_str("process === process"), + njs_str("true") }, + + { njs_str("this.process = 1; process"), + njs_str("1") }, + + { njs_str("Math === Math"), + njs_str("true") }, + + { njs_str("this.Math = 1; Math"), + njs_str("1") }, + + { njs_str("JSON === JSON"), + njs_str("true") }, + + { njs_str("this.JSON = 1; JSON"), + njs_str("1") }, + + { njs_str("delete this.JSON; JSON"), + njs_str("ReferenceError: \"JSON\" is not defined in 1") }, + /* JSON.parse() */ { njs_str("JSON.parse('null')"), diff -r 796870eab669 -r ba6f17a75b3a test/njs_expect_test.exp --- a/test/njs_expect_test.exp Thu Oct 31 18:17:30 2019 +0300 +++ b/test/njs_expect_test.exp Thu Oct 31 18:17:31 2019 +0300 @@ -120,8 +120,8 @@ njs_test { njs_test { {"Ma\t" - "Ma\a*th"} - {".\t\t" + "Ma\a*th."} + {"\t\t" "Math.abs*Math.atan2"} } From xeioex at nginx.com Thu Oct 31 15:18:03 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:03 +0000 Subject: [njs] Moving constructors to global object. Message-ID: details: https://hg.nginx.org/njs/rev/c75a8fc6d534 branches: changeset: 1211:c75a8fc6d534 user: Dmitry Volyntsev date: Thu Oct 31 18:17:31 2019 +0300 description: Moving constructors to global object. diffstat: src/njs_array.c | 2 +- src/njs_builtin.c | 240 ++++++++++++++++++++++++++++++++++++--- src/njs_crypto.c | 8 +- src/njs_date.c | 2 +- src/njs_error.c | 28 ++-- src/njs_error.h | 22 +- src/njs_extern.c | 2 +- src/njs_fs.c | 2 +- src/njs_function.c | 4 +- src/njs_generator.c | 19 +-- src/njs_lexer.h | 18 -- src/njs_lexer_keyword.c | 20 --- src/njs_module.c | 2 +- src/njs_object.c | 13 +- src/njs_object_hash.h | 265 +++++++++++++++++++++++++++++++++++++++---- src/njs_parser.c | 6 +- src/njs_parser.h | 8 +- src/njs_parser_expression.c | 7 - src/njs_parser_terminal.c | 68 ----------- src/njs_regexp.c | 2 +- src/njs_vm.c | 4 +- src/njs_vm.h | 121 +++++-------------- src/test/njs_benchmark.c | 23 +++ src/test/njs_unit_test.c | 29 ++++- test/njs_expect_test.exp | 4 +- 25 files changed, 598 insertions(+), 321 deletions(-) diffs (truncated from 1630 to 1000 lines): diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_array.c --- a/src/njs_array.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_array.c Thu Oct 31 18:17:31 2019 +0300 @@ -63,7 +63,7 @@ njs_array_alloc(njs_vm_t *vm, uint64_t l array->start = array->data; njs_lvlhsh_init(&array->object.hash); array->object.shared_hash = vm->shared->array_instance_hash; - array->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_ARRAY].object; + array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_ARRAY].object; array->object.type = NJS_ARRAY; array->object.shared = 0; array->object.extensible = 1; diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 @@ -39,8 +39,8 @@ const njs_object_init_t *njs_object_ini const njs_object_init_t *njs_module_init[] = { - &njs_fs_object_init, /* fs */ - &njs_crypto_object_init, /* crypto */ + &njs_fs_object_init, + &njs_crypto_object_init, NULL }; @@ -64,6 +64,7 @@ const njs_object_init_t *njs_prototype_ &njs_syntax_error_prototype_init, &njs_type_error_prototype_init, &njs_uri_error_prototype_init, + &njs_internal_error_prototype_init, NULL }; @@ -324,7 +325,7 @@ njs_builtin_objects_create(njs_vm_t *vm) prototype++; } - shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = + shared->prototypes[NJS_OBJ_TYPE_REGEXP].regexp.pattern = shared->empty_regexp_pattern; string_object = &shared->string_object; @@ -453,7 +454,6 @@ njs_builtin_objects_clone(njs_vm_t *vm, { size_t size; njs_uint_t i; - njs_value_t *values; njs_object_t *object_prototype, *function_prototype, *error_prototype, *error_constructor; @@ -461,36 +461,32 @@ njs_builtin_objects_clone(njs_vm_t *vm, * Copy both prototypes and constructors arrays by one memcpy() * because they are stored together. */ - size = NJS_PROTOTYPE_MAX * sizeof(njs_object_prototype_t) - + NJS_CONSTRUCTOR_MAX * sizeof(njs_function_t); + size = (sizeof(njs_object_prototype_t) + sizeof(njs_function_t)) + * NJS_OBJ_TYPE_MAX; memcpy(vm->prototypes, vm->shared->prototypes, size); - object_prototype = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + object_prototype = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; - for (i = NJS_PROTOTYPE_ARRAY; i < NJS_PROTOTYPE_EVAL_ERROR; i++) { + for (i = NJS_OBJ_TYPE_ARRAY; i < NJS_OBJ_TYPE_EVAL_ERROR; i++) { vm->prototypes[i].object.__proto__ = object_prototype; } - error_prototype = &vm->prototypes[NJS_PROTOTYPE_ERROR].object; + error_prototype = &vm->prototypes[NJS_OBJ_TYPE_ERROR].object; - for (i = NJS_PROTOTYPE_EVAL_ERROR; i < NJS_PROTOTYPE_MAX; i++) { + for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) { vm->prototypes[i].object.__proto__ = error_prototype; } - values = vm->scopes[NJS_SCOPE_GLOBAL]; + function_prototype = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object; - function_prototype = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; - - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_EVAL_ERROR; i++) { - njs_set_function(&values[i], &vm->constructors[i]); + for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_EVAL_ERROR; i++) { vm->constructors[i].object.__proto__ = function_prototype; } - error_constructor = &vm->constructors[NJS_CONSTRUCTOR_ERROR].object; + error_constructor = &vm->constructors[NJS_OBJ_TYPE_ERROR].object; - for (i = NJS_CONSTRUCTOR_EVAL_ERROR; i < NJS_CONSTRUCTOR_MAX; i++) { - njs_set_function(&values[i], &vm->constructors[i]); + for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) { vm->constructors[i].object.__proto__ = error_constructor; } @@ -501,7 +497,7 @@ njs_builtin_objects_clone(njs_vm_t *vm, njs_set_object(global, &vm->global_object); vm->string_object = vm->shared->string_object; - vm->string_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object; + vm->string_object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_STRING].object; return NJS_OK; } @@ -1090,6 +1086,51 @@ njs_top_level_object(njs_vm_t *vm, njs_o } +static njs_int_t +njs_top_level_constructor(njs_vm_t *vm, njs_object_prop_t *self, + njs_value_t *global, njs_value_t *setval, njs_value_t *retval) +{ + njs_int_t ret; + njs_function_t *ctor; + njs_object_prop_t *prop; + njs_lvlhsh_query_t lhq; + + if (njs_slow_path(setval != NULL)) { + *retval = *setval; + + } else { + ctor = &vm->constructors[self->value.data.magic16]; + + njs_set_function(retval, ctor); + } + + prop = njs_object_prop_alloc(vm, &self->name, retval, 1); + if (njs_slow_path(prop == NULL)) { + return NJS_ERROR; + } + + /* GC */ + + prop->value = *retval; + prop->enumerable = 0; + + lhq.value = prop; + njs_string_get(&self->name, &lhq.key); + lhq.key_hash = self->value.data.magic32; + lhq.replace = 1; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_object_hash_proto; + + ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq); + if (njs_slow_path(ret != NJS_OK)) { + njs_internal_error(vm, "lvlhsh insert/replace failed"); + return NJS_ERROR; + } + + return NJS_OK; +} + + static const njs_object_prop_t njs_global_this_object_properties[] = { /* Global constants. */ @@ -1264,6 +1305,167 @@ static const njs_object_prop_t njs_glob .configurable = 1, }, + /* Global constructors. */ + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Object"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_OBJECT, NJS_OBJECT_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Array"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_ARRAY, NJS_ARRAY_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Boolean"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_BOOLEAN, NJS_BOOLEAN_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Number"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_NUMBER, NJS_NUMBER_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("String"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_STRING, NJS_STRING_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Function"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_FUNCTION, NJS_FUNCTION_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("RegExp"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_REGEXP, NJS_REGEXP_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Date"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_DATE, NJS_DATE_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("Error"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_ERROR, NJS_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("EvalError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_EVAL_ERROR, + NJS_EVAL_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("InternalError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_INTERNAL_ERROR, + NJS_INTERNAL_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("RangeError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_RANGE_ERROR, + NJS_RANGE_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("ReferenceError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_REF_ERROR, NJS_REF_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("SyntaxError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_SYNTAX_ERROR, + NJS_SYNTAX_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("TypeError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_TYPE_ERROR, + NJS_TYPE_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("URIError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_URI_ERROR, + NJS_URI_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("MemoryError"), + .value = njs_prop_handler2(njs_top_level_constructor, + NJS_OBJ_TYPE_MEMORY_ERROR, + NJS_MEMORY_ERROR_HASH), + .writable = 1, + .configurable = 1, + }, }; diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_crypto.c --- a/src/njs_crypto.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_crypto.c Thu Oct 31 18:17:31 2019 +0300 @@ -122,7 +122,7 @@ static njs_crypto_enc_t *njs_crypto_enco static njs_object_value_t * -njs_crypto_object_value_alloc(njs_vm_t *vm, njs_uint_t proto) +njs_crypto_object_value_alloc(njs_vm_t *vm, njs_object_type_t type) { njs_object_value_t *ov; @@ -135,7 +135,7 @@ njs_crypto_object_value_alloc(njs_vm_t * ov->object.shared = 0; ov->object.extensible = 1; - ov->object.__proto__ = &vm->prototypes[proto].object; + ov->object.__proto__ = &vm->prototypes[type].object; return ov; } @@ -166,7 +166,7 @@ njs_crypto_create_hash(njs_vm_t *vm, njs return NJS_ERROR; } - hash = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HASH); + hash = njs_crypto_object_value_alloc(vm, NJS_OBJ_TYPE_CRYPTO_HASH); if (njs_slow_path(hash == NULL)) { return NJS_ERROR; } @@ -431,7 +431,7 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs alg->init(&ctx->u); alg->update(&ctx->u, key_buf, 64); - hmac = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HMAC); + hmac = njs_crypto_object_value_alloc(vm, NJS_OBJ_TYPE_CRYPTO_HMAC); if (njs_slow_path(hmac == NULL)) { return NJS_ERROR; } diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_date.c --- a/src/njs_date.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_date.c Thu Oct 31 18:17:31 2019 +0300 @@ -257,7 +257,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v date->object.type = NJS_DATE; date->object.shared = 0; date->object.extensible = 1; - date->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_DATE].object; + date->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_DATE].object; date->time = njs_timeclip(time); diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_error.c --- a/src/njs_error.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_error.c Thu Oct 31 18:17:31 2019 +0300 @@ -13,7 +13,7 @@ static const njs_value_t njs_error_name void -njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, +njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type, u_char *start, size_t size) { ssize_t length; @@ -41,7 +41,7 @@ njs_error_new(njs_vm_t *vm, njs_value_t void -njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, +njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type, const char *fmt, ...) { va_list args; @@ -60,7 +60,7 @@ njs_error_fmt_new(njs_vm_t *vm, njs_valu njs_object_t * -njs_error_alloc(njs_vm_t *vm, njs_prototype_t type, const njs_value_t *name, +njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name, const njs_value_t *message) { njs_int_t ret; @@ -136,7 +136,7 @@ memory_error: static njs_int_t njs_error_create(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_prototype_t type) + njs_object_type_t type) { njs_int_t ret; njs_value_t *value; @@ -169,7 +169,7 @@ njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_ERROR); } @@ -211,7 +211,7 @@ njs_int_t njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_EVAL_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_EVAL_ERROR); } @@ -253,7 +253,7 @@ njs_int_t njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_INTERNAL_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_INTERNAL_ERROR); } @@ -295,7 +295,7 @@ njs_int_t njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_RANGE_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_RANGE_ERROR); } @@ -337,7 +337,7 @@ njs_int_t njs_reference_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_REF_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_REF_ERROR); } @@ -379,7 +379,7 @@ njs_int_t njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_SYNTAX_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_SYNTAX_ERROR); } @@ -421,7 +421,7 @@ njs_int_t njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_TYPE_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_TYPE_ERROR); } @@ -463,7 +463,7 @@ njs_int_t njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - return njs_error_create(vm, args, nargs, NJS_PROTOTYPE_URI_ERROR); + return njs_error_create(vm, args, nargs, NJS_OBJ_TYPE_URI_ERROR); } @@ -512,7 +512,7 @@ njs_memory_error_set(njs_vm_t *vm, njs_v njs_lvlhsh_init(&object->hash); njs_lvlhsh_init(&object->shared_hash); - object->__proto__ = &prototypes[NJS_PROTOTYPE_INTERNAL_ERROR].object; + object->__proto__ = &prototypes[NJS_OBJ_TYPE_INTERNAL_ERROR].object; object->type = NJS_OBJECT; object->shared = 1; @@ -554,7 +554,7 @@ njs_memory_error_prototype_create(njs_vm /* MemoryError has no its own prototype. */ - index = NJS_PROTOTYPE_INTERNAL_ERROR; + index = NJS_OBJ_TYPE_INTERNAL_ERROR; function = njs_function(value); proto = njs_property_prototype_create(vm, &function->object.hash, diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_error.h --- a/src/njs_error.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_error.h Thu Oct 31 18:17:31 2019 +0300 @@ -9,38 +9,38 @@ #define njs_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_ERROR, fmt, ##__VA_ARGS__) + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_ERROR, fmt, ##__VA_ARGS__) #define njs_eval_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_EVAL_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_EVAL_ERROR, fmt, \ ##__VA_ARGS__) #define njs_internal_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_INTERNAL_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_INTERNAL_ERROR, fmt, \ ##__VA_ARGS__) #define njs_range_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_RANGE_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_RANGE_ERROR, fmt, \ ##__VA_ARGS__) #define njs_reference_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_REF_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_REF_ERROR, fmt, \ ##__VA_ARGS__) #define njs_syntax_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_SYNTAX_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_SYNTAX_ERROR, fmt, \ ##__VA_ARGS__) #define njs_type_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_TYPE_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_TYPE_ERROR, fmt, \ ##__VA_ARGS__) #define njs_uri_error(vm, fmt, ...) \ - njs_error_fmt_new(vm, &vm->retval, NJS_PROTOTYPE_URI_ERROR, fmt, \ + njs_error_fmt_new(vm, &vm->retval, NJS_OBJ_TYPE_URI_ERROR, fmt, \ ##__VA_ARGS__) -void njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_prototype_t type, +void njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type, u_char *start, size_t size); void njs_noinline njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, - njs_prototype_t type, const char *fmt, ...); + njs_object_type_t type, const char *fmt, ...); void njs_memory_error(njs_vm_t *vm); void njs_memory_error_set(njs_vm_t *vm, njs_value_t *value); -njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_prototype_t type, +njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name, const njs_value_t *message); njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_extern.c --- a/src/njs_extern.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_extern.c Thu Oct 31 18:17:31 2019 +0300 @@ -106,7 +106,7 @@ njs_vm_external_add(njs_vm_t *vm, njs_lv */ function->object.__proto__ = - &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; + &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object; function->object.shared_hash = vm->shared->arrow_instance_hash; function->object.type = NJS_FUNCTION; function->object.shared = 1; diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_fs.c --- a/src/njs_fs.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_fs.c Thu Oct 31 18:17:31 2019 +0300 @@ -1028,7 +1028,7 @@ njs_fs_error(njs_vm_t *vm, const char *s return NJS_ERROR; } - error = njs_error_alloc(vm, NJS_PROTOTYPE_ERROR, NULL, &string); + error = njs_error_alloc(vm, NJS_OBJ_TYPE_ERROR, NULL, &string); if (njs_slow_path(error == NULL)) { return NJS_ERROR; } diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_function.c --- a/src/njs_function.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_function.c Thu Oct 31 18:17:31 2019 +0300 @@ -46,7 +46,7 @@ njs_function_alloc(njs_vm_t *vm, njs_fun function->object.shared_hash = vm->shared->arrow_instance_hash; } - function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; + function->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object; function->object.type = NJS_FUNCTION; function->object.shared = shared; function->object.extensible = 1; @@ -122,7 +122,7 @@ njs_function_copy(njs_vm_t *vm, njs_func } *copy = *function; - copy->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; + copy->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object; copy->object.shared = 0; if (nesting == 0) { diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_generator.c --- a/src/njs_generator.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_generator.c Thu Oct 31 18:17:31 2019 +0300 @@ -247,7 +247,7 @@ static njs_int_t njs_generate_function_d #define njs_generate_syntax_error(vm, node, fmt, ...) \ - njs_parser_node_error(vm, node, NJS_PROTOTYPE_SYNTAX_ERROR, fmt, \ + njs_parser_node_error(vm, node, NJS_OBJ_TYPE_SYNTAX_ERROR, fmt, \ ##__VA_ARGS__) @@ -417,23 +417,6 @@ njs_generate(njs_vm_t *vm, njs_generator return njs_generate_template_literal(vm, generator, node); case NJS_TOKEN_THIS: - case NJS_TOKEN_OBJECT_CONSTRUCTOR: - case NJS_TOKEN_ARRAY_CONSTRUCTOR: - case NJS_TOKEN_NUMBER_CONSTRUCTOR: - case NJS_TOKEN_BOOLEAN_CONSTRUCTOR: - case NJS_TOKEN_STRING_CONSTRUCTOR: - case NJS_TOKEN_FUNCTION_CONSTRUCTOR: - case NJS_TOKEN_REGEXP_CONSTRUCTOR: - case NJS_TOKEN_DATE_CONSTRUCTOR: - case NJS_TOKEN_ERROR_CONSTRUCTOR: - case NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR: - case NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR: - case NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR: - case NJS_TOKEN_REF_ERROR_CONSTRUCTOR: - case NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR: - case NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR: - case NJS_TOKEN_URI_ERROR_CONSTRUCTOR: - case NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR: case NJS_TOKEN_EXTERNAL: return NJS_OK; diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_lexer.h --- a/src/njs_lexer.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_lexer.h Thu Oct 31 18:17:31 2019 +0300 @@ -171,24 +171,6 @@ typedef enum { NJS_TOKEN_ARGUMENTS, NJS_TOKEN_EVAL, - NJS_TOKEN_OBJECT_CONSTRUCTOR, - NJS_TOKEN_ARRAY_CONSTRUCTOR, - NJS_TOKEN_BOOLEAN_CONSTRUCTOR, - NJS_TOKEN_NUMBER_CONSTRUCTOR, - NJS_TOKEN_STRING_CONSTRUCTOR, - NJS_TOKEN_FUNCTION_CONSTRUCTOR, - NJS_TOKEN_REGEXP_CONSTRUCTOR, - NJS_TOKEN_DATE_CONSTRUCTOR, - NJS_TOKEN_ERROR_CONSTRUCTOR, - NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR, - NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR, - NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR, - NJS_TOKEN_REF_ERROR_CONSTRUCTOR, - NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR, - NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR, - NJS_TOKEN_URI_ERROR_CONSTRUCTOR, - NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, - NJS_TOKEN_IMPORT, NJS_TOKEN_EXPORT, diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_lexer_keyword.c --- a/src/njs_lexer_keyword.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_lexer_keyword.c Thu Oct 31 18:17:31 2019 +0300 @@ -47,26 +47,6 @@ static const njs_keyword_t njs_keywords { njs_str("finally"), NJS_TOKEN_FINALLY, 0 }, { njs_str("throw"), NJS_TOKEN_THROW, 0 }, - /* Builtin functions. */ - - { njs_str("Object"), NJS_TOKEN_OBJECT_CONSTRUCTOR, 0 }, - { njs_str("Array"), NJS_TOKEN_ARRAY_CONSTRUCTOR, 0 }, - { njs_str("Boolean"), NJS_TOKEN_BOOLEAN_CONSTRUCTOR, 0 }, - { njs_str("Number"), NJS_TOKEN_NUMBER_CONSTRUCTOR, 0 }, - { njs_str("String"), NJS_TOKEN_STRING_CONSTRUCTOR, 0 }, - { njs_str("Function"), NJS_TOKEN_FUNCTION_CONSTRUCTOR, 0 }, - { njs_str("RegExp"), NJS_TOKEN_REGEXP_CONSTRUCTOR, 0 }, - { njs_str("Date"), NJS_TOKEN_DATE_CONSTRUCTOR, 0 }, - { njs_str("Error"), NJS_TOKEN_ERROR_CONSTRUCTOR, 0 }, - { njs_str("EvalError"), NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR, 0 }, - { njs_str("InternalError"), NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR, 0 }, - { njs_str("RangeError"), NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR, 0 }, - { njs_str("ReferenceError"), NJS_TOKEN_REF_ERROR_CONSTRUCTOR, 0 }, - { njs_str("SyntaxError"), NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR, 0 }, - { njs_str("TypeError"), NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR, 0 }, - { njs_str("URIError"), NJS_TOKEN_URI_ERROR_CONSTRUCTOR, 0 }, - { njs_str("MemoryError"), NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, 0 }, - /* Module. */ { njs_str("import"), NJS_TOKEN_IMPORT, 0 }, diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_module.c --- a/src/njs_module.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_module.c Thu Oct 31 18:17:31 2019 +0300 @@ -537,7 +537,7 @@ njs_module_require(njs_vm_t *vm, njs_val } *object = module->object; - object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; object->shared = 0; object->error_data = 0; diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_object.c --- a/src/njs_object.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object.c Thu Oct 31 18:17:31 2019 +0300 @@ -39,7 +39,7 @@ njs_object_alloc(njs_vm_t *vm) if (njs_fast_path(object != NULL)) { njs_lvlhsh_init(&object->hash); njs_lvlhsh_init(&object->shared_hash); - object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; object->type = NJS_OBJECT; object->shared = 0; object->extensible = 1; @@ -68,7 +68,7 @@ njs_object_value_copy(njs_vm_t *vm, njs_ if (njs_fast_path(object != NULL)) { *object = *njs_object(value); - object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; + object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; object->shared = 0; value->data.u.object = object; return object; @@ -1605,7 +1605,7 @@ njs_object_prototype_create(njs_vm_t *vm function = njs_function(value); index = function - vm->constructors; - if (index >= 0 && index < NJS_PROTOTYPE_MAX) { + if (index >= 0 && index < NJS_OBJ_TYPE_MAX) { proto = njs_property_prototype_create(vm, &function->object.hash, &vm->prototypes[index].object); } @@ -1928,7 +1928,7 @@ njs_object_prototype_create_constructor( njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { int32_t index; - njs_value_t *cons; + njs_value_t *cons, constructor; njs_object_t *object; njs_object_prototype_t *prototype; @@ -1939,7 +1939,7 @@ njs_object_prototype_create_constructor( prototype = (njs_object_prototype_t *) object; index = prototype - vm->prototypes; - if (index >= 0 && index < NJS_PROTOTYPE_MAX) { + if (index >= 0 && index < NJS_OBJ_TYPE_MAX) { goto found; } @@ -1959,7 +1959,8 @@ njs_object_prototype_create_constructor( found: if (setval == NULL) { - setval = &vm->scopes[NJS_SCOPE_GLOBAL][index]; + njs_set_function(&constructor, &vm->constructors[index]); + setval = &constructor; } cons = njs_property_constructor_create(vm, &prototype->object.hash, setval); diff -r ba6f17a75b3a -r c75a8fc6d534 src/njs_object_hash.h --- a/src/njs_object_hash.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object_hash.h Thu Oct 31 18:17:31 2019 +0300 @@ -21,6 +21,15 @@ '_'), '_'), 'p'), 'r'), 'o'), 't'), 'o'), '_'), '_') +#define NJS_ARRAY_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'A'), 'r'), 'r'), 'a'), 'y') + + #define NJS_ARGV_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -29,6 +38,17 @@ 'a'), 'r'), 'g'), 'v') +#define NJS_BOOLEAN_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'B'), 'o'), 'o'), 'l'), 'e'), 'a'), 'n') + + #define NJS_CONFIGURABLE_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -60,6 +80,14 @@ 'c'), 'o'), 'n'), 's'), 't'), 'r'), 'u'), 'c'), 't'), 'o'), 'r') +#define NJS_DATE_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'D'), 'a'), 't'), 'e') + + #define NJS_ENUMERABLE_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -83,6 +111,15 @@ 'e'), 'r'), 'r'), 'n'), 'o') +#define NJS_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'E'), 'r'), 'r'), 'o'), 'r') + + #define NJS_ENCODING_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -102,6 +139,19 @@ 'e'), 'n'), 'v') +#define NJS_EVAL_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'E'), 'v'), 'a'), 'l'), 'E'), 'r'), 'r'), 'o'), 'r') + + #define NJS_FLAG_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -110,6 +160,25 @@ 'f'), 'l'), 'a'), 'g') +#define NJS_GET_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'g'), 'e'), 't') + + +#define NJS_FUNCTION_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'F'), 'u'), 'n'), 'c'), 't'), 'i'), 'o'), 'n') + + #define NJS_INDEX_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -128,6 +197,24 @@ 'i'), 'n'), 'p'), 'u'), 't') +#define NJS_INTERNAL_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'I'), 'n'), 't'), 'e'), 'r'), 'n'), 'a'), 'l'), \ + 'E'), 'r'), 'r'), 'o'), 'r') + + #define NJS_GROUPS_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -179,6 +266,16 @@ 'n'), 'j'), 's') +#define NJS_NUMBER_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'N'), 'u'), 'm'), 'b'), 'e'), 'r') + + #define NJS_MATH_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -187,6 +284,22 @@ 'M'), 'a'), 't'), 'h') +#define NJS_MEMORY_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'M'), 'e'), 'm'), 'o'), 'r'), 'y'), \ + 'E'), 'r'), 'r'), 'o'), 'r') + + #define NJS_MESSAGE_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ @@ -206,15 +319,14 @@ 'm'), 'o'), 'd'), 'e') -#define NJS_SYSCALL_HASH \ - njs_djb_hash_add( \ +#define NJS_OBJECT_HASH \ njs_djb_hash_add( \ njs_djb_hash_add( \ njs_djb_hash_add( \ njs_djb_hash_add( \ njs_djb_hash_add( \ njs_djb_hash_add(NJS_DJB_HASH_INIT, \ - 's'), 'y'), 's'), 'c'), 'a'), 'l'), 'l') + 'O'), 'b'), 'j'), 'e'), 'c'), 't') #define NJS_PATH_HASH \ @@ -249,6 +361,93 @@ 'p'), 'r'), 'o'), 't'), 'o'), 't'), 'y'), 'p'), 'e') +#define NJS_RANGE_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'R'), 'a'), 'n'), 'g'), 'e'), 'E'), 'r'), 'r'), 'o'), 'r') + + +#define NJS_REF_ERROR_HASH \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add( \ + njs_djb_hash_add(NJS_DJB_HASH_INIT, \ + 'R'), 'e'), 'f'), 'e'), 'r'), 'e'), 'n'), 'c'), 'e'), \ From xeioex at nginx.com Thu Oct 31 15:18:03 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:03 +0000 Subject: [njs] Refactored completions and backtrace matches. Message-ID: details: https://hg.nginx.org/njs/rev/2868545c461b branches: changeset: 1212:2868545c461b user: Dmitry Volyntsev date: Thu Oct 31 18:17:31 2019 +0300 description: Refactored completions and backtrace matches. diffstat: src/njs_builtin.c | 460 ++++++++++++++++++++++------------------------ src/njs_crypto.c | 56 +++++- src/njs_object.c | 81 ++++++++ src/njs_object.h | 20 ++ src/njs_value.c | 1 + src/njs_value.h | 1 + test/njs_expect_test.exp | 4 +- 7 files changed, 381 insertions(+), 242 deletions(-) diffs (808 lines): diff -r c75a8fc6d534 -r 2868545c461b src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 @@ -14,6 +14,19 @@ typedef struct { } njs_function_init_t; +typedef struct { + enum { + NJS_BUILTIN_TRAVERSE_KEYS, + NJS_BUILTIN_TRAVERSE_MATCH, + } type; + + njs_function_native_t native; + + njs_lvlhsh_t keys; + njs_str_t match; +} njs_builtin_traverse_t; + + static njs_int_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); static njs_arr_t *njs_vm_expression_completions(njs_vm_t *vm, @@ -503,17 +516,130 @@ njs_builtin_objects_clone(njs_vm_t *vm, } -static size_t -njs_builtin_completions_size(njs_vm_t *vm) +static njs_int_t +njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data) { - njs_uint_t n; + size_t len; + u_char *p, *start, *end; + njs_int_t ret, n; + njs_str_t name; + njs_object_prop_t *prop; + njs_lvlhsh_query_t lhq; + njs_builtin_traverse_t *ctx; + njs_traverse_t *path[NJS_TRAVERSE_MAX_DEPTH]; + u_char buf[256]; + + ctx = data; + + if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) { + prop = traverse->prop; + + if (!(njs_is_function(&prop->value) + && njs_function(&prop->value)->native + && njs_function(&prop->value)->u.native == ctx->native)) + { + return NJS_OK; + } + } + + n = 0; + + while (traverse != NULL) { + path[n++] = traverse; + traverse = traverse->parent; + } + + n--; + + p = buf; + end = buf + sizeof(buf); + + do { + njs_string_get(&path[n]->prop->name, &name); + + if (njs_slow_path((p + name.length + 1) > end)) { + njs_type_error(vm, "njs_builtin_traverse() key is too long"); + return NJS_ERROR; + } + + p = njs_cpymem(p, name.start, name.length); + + if (n != 0) { + *p++ = '.'; + } + + } while (n-- > 0); + + if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) { + len = ctx->match.length; + start = njs_mp_alloc(vm->mem_pool, len + (p - buf) + (len != 0)); + if (njs_slow_path(start == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + if (len != 0) { + memcpy(start, ctx->match.start, len); + start[len++] = '.'; + } + + memcpy(start + len, buf, p - buf); + ctx->match.length = len + p - buf; + ctx->match.start = start; + + return NJS_DONE; + } + + /* NJS_BUILTIN_TRAVERSE_KEYS. */ + + prop = njs_object_prop_alloc(vm, &njs_value_undefined, &njs_value_null, 0); + if (njs_slow_path(prop == NULL)) { + return NJS_ERROR; + } + + ret = njs_string_new(vm, &prop->name, buf, p - buf, 0); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + lhq.value = prop; + njs_string_get(&prop->name, &lhq.key); + lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); + lhq.replace = 1; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_object_hash_proto; + + ret = njs_lvlhsh_insert(&ctx->keys, &lhq); + if (njs_slow_path(ret != NJS_OK)) { + njs_internal_error(vm, "lvlhsh insert/replace failed"); + return NJS_ERROR; + } + + return NJS_OK; +} + + +static njs_arr_t * +njs_builtin_completions(njs_vm_t *vm) +{ + u_char *compl; + size_t len; + njs_arr_t *array; + njs_str_t *completion; + njs_int_t ret; njs_keyword_t *keyword; njs_lvlhsh_each_t lhe, lhe_prop; njs_extern_value_t *ev; const njs_extern_t *ext_proto, *ext_prop; - const njs_object_init_t **p; + njs_builtin_traverse_t ctx; + const njs_object_prop_t *prop; - n = 0; + array = njs_arr_create(vm->mem_pool, 64, sizeof(njs_str_t)); + if (njs_slow_path(array == NULL)) { + return NULL; + } + + /* Keywords completions. */ njs_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); @@ -524,149 +650,43 @@ njs_builtin_completions_size(njs_vm_t *v break; } - n++; - } - - for (p = njs_object_init; *p != NULL; p++) { - n += (*p)->items; - } - - for (p = njs_prototype_init; *p != NULL; p++) { - n += (*p)->items; - } - - for (p = njs_constructor_init; *p != NULL; p++) { - n += (*p)->items; - } - - njs_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); - - for ( ;; ) { - ev = njs_lvlhsh_each(&vm->externals_hash, &lhe); - - if (ev == NULL) { - break; + completion = njs_arr_add(array); + if (njs_slow_path(completion == NULL)) { + return NULL; } - ext_proto = ev->value.external.proto; - - njs_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); - - n++; - - for ( ;; ) { - ext_prop = njs_lvlhsh_each(&ext_proto->hash, &lhe_prop); - - if (ext_prop == NULL) { - break; - } - - n++; - } + *completion = keyword->name; } - return n; -} + /* Global object completions. */ + ctx.type = NJS_BUILTIN_TRAVERSE_KEYS; + njs_lvlhsh_init(&ctx.keys); -static njs_arr_t * -njs_builtin_completions(njs_vm_t *vm, njs_arr_t *array) -{ - u_char *compl; - size_t n, len; - njs_str_t string, *completions; - njs_uint_t i, k; - njs_keyword_t *keyword; - njs_lvlhsh_each_t lhe, lhe_prop; - njs_extern_value_t *ev; - const njs_extern_t *ext_proto, *ext_prop; - const njs_object_prop_t *prop; - const njs_object_init_t *obj, **p; + ret = njs_object_traverse(vm, &vm->global_object, &ctx, + njs_builtin_traverse); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } - n = 0; - completions = array->start; - - njs_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); + njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto); for ( ;; ) { - keyword = njs_lvlhsh_each(&vm->shared->keywords_hash, &lhe); + prop = njs_lvlhsh_each(&ctx.keys, &lhe); - if (keyword == NULL) { + if (prop == NULL) { break; } - completions[n++] = keyword->name; - } - - for (p = njs_object_init; *p != NULL; p++) { - obj = *p; - - for (i = 0; i < obj->items; i++) { - prop = &obj->properties[i]; - njs_string_get(&prop->name, &string); - len = obj->name.length + string.length + 2; + completion = njs_arr_add(array); + if (njs_slow_path(completion == NULL)) { + return NULL; + } - compl = njs_mp_zalloc(vm->mem_pool, len); - if (compl == NULL) { - return NULL; - } - - njs_sprintf(compl, compl + len, "%s.%s%Z", obj->name.start, - string.start); - - completions[n].length = len; - completions[n++].start = (u_char *) compl; - } + njs_string_get(&prop->name, completion); } - for (p = njs_prototype_init; *p != NULL; p++) { - obj = *p; - - for (i = 0; i < obj->items; i++) { - prop = &obj->properties[i]; - njs_string_get(&prop->name, &string); - len = string.length + 2; - - compl = njs_mp_zalloc(vm->mem_pool, len); - if (compl == NULL) { - return NULL; - } - - njs_sprintf(compl, compl + len, ".%s%Z", string.start); - - for (k = 0; k < n; k++) { - if (njs_strncmp(completions[k].start, compl, len) == 0) { - break; - } - } - - if (k == n) { - completions[n].length = len; - completions[n++].start = (u_char *) compl; - } - } - } - - for (p = njs_constructor_init; *p != NULL; p++) { - obj = *p; - - for (i = 0; i < obj->items; i++) { - prop = &obj->properties[i]; - njs_string_get(&prop->name, &string); - len = obj->name.length + string.length + 2; - - compl = njs_mp_zalloc(vm->mem_pool, len); - if (compl == NULL) { - return NULL; - } - - njs_sprintf(compl, compl + len, "%s.%s%Z", obj->name.start, - string.start); - - completions[n].length = len; - completions[n++].start = (u_char *) compl; - } - } + /* Externals completions. */ njs_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); @@ -689,8 +709,13 @@ njs_builtin_completions(njs_vm_t *vm, nj njs_sprintf(compl, compl + len, "%V%Z", &ev->name); - completions[n].length = len; - completions[n++].start = (u_char *) compl; + completion = njs_arr_add(array); + if (njs_slow_path(completion == NULL)) { + return NULL; + } + + completion->length = len; + completion->start = (u_char *) compl; for ( ;; ) { ext_prop = njs_lvlhsh_each(&ext_proto->hash, &lhe_prop); @@ -708,13 +733,16 @@ njs_builtin_completions(njs_vm_t *vm, nj njs_sprintf(compl, compl + len, "%V.%V%Z", &ev->name, &ext_prop->name); - completions[n].length = len; - completions[n++].start = (u_char *) compl; + completion = njs_arr_add(array); + if (njs_slow_path(completion == NULL)) { + return NULL; + } + + completion->length = len; + completion->start = (u_char *) compl; } } - array->items = n; - return array; } @@ -722,18 +750,8 @@ njs_builtin_completions(njs_vm_t *vm, nj njs_arr_t * njs_vm_completions(njs_vm_t *vm, njs_str_t *expression) { - size_t size; - njs_arr_t *completions; - if (expression == NULL) { - size = njs_builtin_completions_size(vm); - - completions = njs_arr_create(vm->mem_pool, size, sizeof(njs_str_t)); - if (njs_slow_path(completions == NULL)) { - return NULL; - } - - return njs_builtin_completions(vm, completions); + return njs_builtin_completions(vm); } return njs_vm_expression_completions(vm, expression); @@ -913,34 +931,71 @@ njs_object_completions(njs_vm_t *vm, njs } -static njs_int_t -njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function, - const njs_object_prop_t **prop, const njs_object_init_t **object) +njs_int_t +njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, + njs_str_t *name) { - njs_uint_t i; - njs_function_t *fun; - const njs_object_init_t *o, **p; - const njs_object_prop_t *pr; + njs_int_t ret; + njs_uint_t i; + njs_value_t value; + njs_module_t *module; + njs_lvlhsh_each_t lhe; + njs_builtin_traverse_t ctx; + + ctx.type = NJS_BUILTIN_TRAVERSE_MATCH; + ctx.native = function->u.native; + + /* Global object. */ - for (p = objects; *p != NULL; p++) { - o = *p; + ctx.match = njs_str_value(""); + + ret = njs_object_traverse(vm, &vm->global_object, &ctx, + njs_builtin_traverse); + + if (ret == NJS_DONE) { + *name = ctx.match; + return NJS_OK; + } + + /* Constructor from built-in modules (not-mapped to global object). */ + + for (i = NJS_OBJ_TYPE_CRYPTO_HASH; i < NJS_OBJ_TYPE_ERROR; i++) { + njs_set_object(&value, &vm->constructors[i].object); - for (i = 0; i < o->items; i++) { - pr = &o->properties[i]; + ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name), + &value); + + if (ret == NJS_OK && njs_is_string(&value)) { + njs_string_get(&value, &ctx.match); + } - if (pr->type != NJS_PROPERTY || !njs_is_function(&pr->value)) { - continue; - } + ret = njs_object_traverse(vm, &vm->constructors[i].object, &ctx, + njs_builtin_traverse); + + if (ret == NJS_DONE) { + *name = ctx.match; + return NJS_OK; + } + } - fun = njs_function(&pr->value); + /* Modules. */ + + njs_lvlhsh_each_init(&lhe, &njs_modules_hash_proto); + + for ( ;; ) { + module = njs_lvlhsh_each(&vm->modules_hash, &lhe); - if (function->u.native != fun->u.native) { - continue; - } + if (module == NULL) { + break; + } + + ctx.match = module->name; - *prop = pr; - *object = o; + ret = njs_object_traverse(vm, &module->object, &ctx, + njs_builtin_traverse); + if (ret == NJS_DONE) { + *name = ctx.match; return NJS_OK; } } @@ -949,68 +1004,6 @@ njs_builtin_match(const njs_object_init_ } -njs_int_t -njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, - njs_str_t *name) -{ - size_t len; - njs_str_t string, middle; - njs_int_t ret; - const njs_object_init_t *obj; - const njs_object_prop_t *prop; - - middle = njs_str_value("."); - - ret = njs_builtin_match(njs_object_init, function, &prop, &obj); - - if (ret == NJS_OK) { - if (!obj->name.length) { - middle = njs_str_value(""); - } - - goto found; - } - - ret = njs_builtin_match(njs_prototype_init, function, &prop, &obj); - - if (ret == NJS_OK) { - middle = njs_str_value(".prototype."); - goto found; - } - - ret = njs_builtin_match(njs_constructor_init, function, &prop, &obj); - - if (ret == NJS_OK) { - goto found; - } - - ret = njs_builtin_match(njs_module_init, function, &prop, &obj); - - if (ret == NJS_OK) { - goto found; - } - - return NJS_DECLINED; - -found: - - njs_string_get(&prop->name, &string); - - len = obj->name.length + middle.length + string.length; - - name->length = len; - name->start = njs_mp_zalloc(vm->mem_pool, len); - if (name->start == NULL) { - return NJS_ERROR; - } - - njs_sprintf(name->start, name->start + len, - "%V%V%V", &obj->name, &middle, &string); - - return NJS_OK; -} - - static njs_int_t njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) @@ -1515,11 +1508,6 @@ njs_process_object_argv(njs_vm_t *vm, nj static const njs_value_t argv_string = njs_string("argv"); - if (njs_slow_path(vm->options.argv == NULL)) { - njs_internal_error(vm, "argv was not provided by host environment"); - return NJS_ERROR; - } - argv = njs_array_alloc(vm, vm->options.argc, 0); if (njs_slow_path(argv == NULL)) { return NJS_ERROR; diff -r c75a8fc6d534 -r 2868545c461b src/njs_crypto.c --- a/src/njs_crypto.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_crypto.c Thu Oct 31 18:17:31 2019 +0300 @@ -361,10 +361,34 @@ njs_hash_constructor(njs_vm_t *vm, njs_v } +static const njs_object_prop_t njs_hash_constructor_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("Hash"), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 2.0), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("prototype"), + .value = njs_prop_handler(njs_object_prototype_create), + }, +}; + + const njs_object_init_t njs_hash_constructor_init = { njs_str("Hash"), - NULL, - 0, + njs_hash_constructor_properties, + njs_nitems(njs_hash_constructor_properties), }; @@ -621,10 +645,34 @@ njs_hmac_constructor(njs_vm_t *vm, njs_v } +static const njs_object_prop_t njs_hmac_constructor_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("Hmac"), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 3.0), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("prototype"), + .value = njs_prop_handler(njs_object_prototype_create), + }, +}; + + const njs_object_init_t njs_hmac_constructor_init = { njs_str("Hmac"), - NULL, - 0, + njs_hmac_constructor_properties, + njs_nitems(njs_hmac_constructor_properties), }; diff -r c75a8fc6d534 -r 2868545c461b src/njs_object.c --- a/src/njs_object.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object.c Thu Oct 31 18:17:31 2019 +0300 @@ -1084,6 +1084,87 @@ njs_object_own_enumerate_object(njs_vm_t } +njs_int_t +njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx, + njs_object_traverse_cb_t cb) +{ + njs_int_t depth, ret; + njs_str_t name; + njs_value_t value, obj; + njs_object_prop_t *prop; + njs_traverse_t state[NJS_TRAVERSE_MAX_DEPTH]; + + static const njs_str_t constructor_key = njs_str("constructor"); + + depth = 0; + + state[depth].prop = NULL; + state[depth].parent = NULL; + state[depth].object = object; + state[depth].hash = &object->shared_hash; + njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto); + + for ( ;; ) { + prop = njs_lvlhsh_each(state[depth].hash, &state[depth].lhe); + + if (prop == NULL) { + if (state[depth].hash == &state[depth].object->shared_hash) { + state[depth].hash = &state[depth].object->hash; + njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto); + continue; + } + + if (depth == 0) { + return NJS_OK; + } + + depth--; + continue; + } + + state[depth].prop = prop; + + ret = cb(vm, &state[depth], ctx); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + value = prop->value; + + if (prop->type == NJS_PROPERTY_HANDLER) { + njs_set_object(&obj, state[depth].object); + ret = prop->value.data.u.prop_handler(vm, prop, &obj, NULL, &value); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + + } + } + + njs_string_get(&prop->name, &name); + + /* + * "constructor" properties make loops in object hierarchies. + * Object.prototype.constructor -> Object. + */ + + if (njs_is_object(&value) && !njs_strstr_eq(&name, &constructor_key)) { + if (++depth > (NJS_TRAVERSE_MAX_DEPTH - 1)) { + njs_type_error(vm, "njs_object_traverse() recursion limit:%d", + depth); + return NJS_ERROR; + } + + state[depth].prop = NULL; + state[depth].parent = &state[depth - 1]; + state[depth].object = njs_object(&value); + state[depth].hash = &njs_object(&value)->shared_hash; + njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto); + } + + } +} + + static njs_int_t njs_object_define_property(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) diff -r c75a8fc6d534 -r 2868545c461b src/njs_object.h --- a/src/njs_object.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object.h Thu Oct 31 18:17:31 2019 +0300 @@ -43,6 +43,24 @@ struct njs_object_init_s { }; +typedef struct njs_traverse_s njs_traverse_t; + +struct njs_traverse_s { + struct njs_traverse_s *parent; + njs_object_prop_t *prop; + + njs_object_t *object; + njs_lvlhsh_t *hash; + njs_lvlhsh_each_t lhe; + +#define NJS_TRAVERSE_MAX_DEPTH 32 +}; + + +typedef njs_int_t (*njs_object_traverse_cb_t)(njs_vm_t *vm, + njs_traverse_t *traverse, void *ctx); + + njs_object_t *njs_object_alloc(njs_vm_t *vm); njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value); njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, @@ -51,6 +69,8 @@ njs_array_t *njs_object_enumerate(njs_vm njs_object_enum_t kind, njs_bool_t all); njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object, njs_object_enum_t kind, njs_bool_t all); +njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx, + njs_object_traverse_cb_t cb); njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash, const njs_object_prop_t *prop, njs_uint_t n); njs_int_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args, diff -r c75a8fc6d534 -r 2868545c461b src/njs_value.c --- a/src/njs_value.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_value.c Thu Oct 31 18:17:31 2019 +0300 @@ -48,6 +48,7 @@ const njs_value_t njs_string_plus_infin njs_string("Infinity"); const njs_value_t njs_string_nan = njs_string("NaN"); const njs_value_t njs_string_string = njs_string("string"); +const njs_value_t njs_string_name = njs_string("name"); const njs_value_t njs_string_data = njs_string("data"); const njs_value_t njs_string_external = njs_string("external"); const njs_value_t njs_string_invalid = njs_string("invalid"); diff -r c75a8fc6d534 -r 2868545c461b src/njs_value.h --- a/src/njs_value.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_value.h Thu Oct 31 18:17:31 2019 +0300 @@ -665,6 +665,7 @@ extern const njs_value_t njs_string_plu extern const njs_value_t njs_string_nan; extern const njs_value_t njs_string_string; extern const njs_value_t njs_string_data; +extern const njs_value_t njs_string_name; extern const njs_value_t njs_string_external; extern const njs_value_t njs_string_invalid; extern const njs_value_t njs_string_object; diff -r c75a8fc6d534 -r 2868545c461b test/njs_expect_test.exp --- a/test/njs_expect_test.exp Thu Oct 31 18:17:31 2019 +0300 +++ b/test/njs_expect_test.exp Thu Oct 31 18:17:31 2019 +0300 @@ -101,7 +101,7 @@ njs_test { njs_test { {"O\t" - "O\a*bject."} + "O\a*bject"} {"\t\t" "Object.create*Object.isSealed"} } @@ -120,7 +120,7 @@ njs_test { njs_test { {"Ma\t" - "Ma\a*th."} + "Ma\a*th"} {"\t\t" "Math.abs*Math.atan2"} } From xeioex at nginx.com Thu Oct 31 15:18:03 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:03 +0000 Subject: [njs] Removing console.help() from CLI as it not needed anymore. Message-ID: details: https://hg.nginx.org/njs/rev/ce17b8cd9630 branches: changeset: 1213:ce17b8cd9630 user: Dmitry Volyntsev date: Thu Oct 31 18:17:32 2019 +0300 description: Removing console.help() from CLI as it not needed anymore. Now all available objects are accessible through the global object. diffstat: src/njs_array.c | 3 --- src/njs_boolean.c | 2 -- src/njs_builtin.c | 18 ++++++++++++++---- src/njs_crypto.c | 5 ----- src/njs_date.c | 2 -- src/njs_error.c | 17 ----------------- src/njs_fs.c | 1 - src/njs_function.c | 6 ------ src/njs_json.c | 1 - src/njs_math.c | 1 - src/njs_number.c | 3 --- src/njs_object.c | 2 -- src/njs_object.h | 1 - src/njs_regexp.c | 2 -- src/njs_shell.c | 47 +---------------------------------------------- src/njs_string.c | 3 --- test/njs_expect_test.exp | 3 --- 17 files changed, 15 insertions(+), 102 deletions(-) diffs (592 lines): diff -r 2868545c461b -r ce17b8cd9630 src/njs_array.c --- a/src/njs_array.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_array.c Thu Oct 31 18:17:32 2019 +0300 @@ -322,7 +322,6 @@ static const njs_object_prop_t njs_arra const njs_object_init_t njs_array_constructor_init = { - njs_str("Array"), njs_array_constructor_properties, njs_nitems(njs_array_constructor_properties), }; @@ -2987,7 +2986,6 @@ static const njs_object_prop_t njs_arra const njs_object_init_t njs_array_prototype_init = { - njs_str("Array"), njs_array_prototype_properties, njs_nitems(njs_array_prototype_properties), }; @@ -3005,7 +3003,6 @@ const njs_object_prop_t njs_array_insta const njs_object_init_t njs_array_instance_init = { - njs_str("Array instance"), njs_array_instance_properties, njs_nitems(njs_array_instance_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_boolean.c --- a/src/njs_boolean.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_boolean.c Thu Oct 31 18:17:32 2019 +0300 @@ -66,7 +66,6 @@ static const njs_object_prop_t njs_bool const njs_object_init_t njs_boolean_constructor_init = { - njs_str("Boolean"), njs_boolean_constructor_properties, njs_nitems(njs_boolean_constructor_properties), }; @@ -161,7 +160,6 @@ static const njs_object_prop_t njs_bool const njs_object_init_t njs_boolean_prototype_init = { - njs_str("Boolean"), njs_boolean_prototype_properties, njs_nitems(njs_boolean_prototype_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:32 2019 +0300 @@ -199,10 +199,12 @@ njs_builtin_objects_create(njs_vm_t *vm) njs_lvlhsh_query_t lhq; njs_regexp_pattern_t *pattern; njs_object_prototype_t *prototype; + const njs_object_prop_t *prop; const njs_object_init_t *obj, **p; const njs_function_init_t *f; static const njs_str_t sandbox_key = njs_str("sandbox"); + static const njs_str_t name_key = njs_str("name"); shared = njs_mp_zalloc(vm->mem_pool, sizeof(njs_vm_shared_t)); if (njs_slow_path(shared == NULL)) { @@ -308,7 +310,18 @@ njs_builtin_objects_create(njs_vm_t *vm) } } - module->name = obj->name; + lhq.key = name_key; + lhq.key_hash = njs_djb_hash(name_key.start, name_key.length); + lhq.proto = &njs_object_hash_proto; + + ret = njs_lvlhsh_find(&module->object.shared_hash, &lhq); + if (njs_fast_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + prop = lhq.value; + + njs_string_get(&prop->value, &module->name); module->object.shared = 1; lhq.key = module->name; @@ -1463,7 +1476,6 @@ static const njs_object_prop_t njs_glob const njs_object_init_t njs_global_this_init = { - njs_str(""), njs_global_this_object_properties, njs_nitems(njs_global_this_object_properties) }; @@ -1489,7 +1501,6 @@ static const njs_object_prop_t njs_njs_ const njs_object_init_t njs_njs_object_init = { - njs_str("njs"), njs_njs_object_properties, njs_nitems(njs_njs_object_properties), }; @@ -1698,7 +1709,6 @@ static const njs_object_prop_t njs_proc const njs_object_init_t njs_process_object_init = { - njs_str("process"), njs_process_object_properties, njs_nitems(njs_process_object_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_crypto.c --- a/src/njs_crypto.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_crypto.c Thu Oct 31 18:17:32 2019 +0300 @@ -347,7 +347,6 @@ static const njs_object_prop_t njs_hash const njs_object_init_t njs_hash_prototype_init = { - njs_str("Hash"), njs_hash_prototype_properties, njs_nitems(njs_hash_prototype_properties), }; @@ -386,7 +385,6 @@ static const njs_object_prop_t njs_hash const njs_object_init_t njs_hash_constructor_init = { - njs_str("Hash"), njs_hash_constructor_properties, njs_nitems(njs_hash_constructor_properties), }; @@ -631,7 +629,6 @@ static const njs_object_prop_t njs_hmac const njs_object_init_t njs_hmac_prototype_init = { - njs_str("Hmac"), njs_hmac_prototype_properties, njs_nitems(njs_hmac_prototype_properties), }; @@ -670,7 +667,6 @@ static const njs_object_prop_t njs_hmac const njs_object_init_t njs_hmac_constructor_init = { - njs_str("Hmac"), njs_hmac_constructor_properties, njs_nitems(njs_hmac_constructor_properties), }; @@ -711,7 +707,6 @@ static const njs_object_prop_t njs_cryp const njs_object_init_t njs_crypto_object_init = { - njs_str("crypto"), njs_crypto_object_properties, njs_nitems(njs_crypto_object_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_date.c --- a/src/njs_date.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_date.c Thu Oct 31 18:17:32 2019 +0300 @@ -1048,7 +1048,6 @@ static const njs_object_prop_t njs_date const njs_object_init_t njs_date_constructor_init = { - njs_str("Date"), njs_date_constructor_properties, njs_nitems(njs_date_constructor_properties), }; @@ -2888,7 +2887,6 @@ static const njs_object_prop_t njs_date const njs_object_init_t njs_date_prototype_init = { - njs_str("Date"), njs_date_prototype_properties, njs_nitems(njs_date_prototype_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_error.c --- a/src/njs_error.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_error.c Thu Oct 31 18:17:32 2019 +0300 @@ -201,7 +201,6 @@ static const njs_object_prop_t njs_erro const njs_object_init_t njs_error_constructor_init = { - njs_str("Error"), njs_error_constructor_properties, njs_nitems(njs_error_constructor_properties), }; @@ -243,7 +242,6 @@ static const njs_object_prop_t njs_eval const njs_object_init_t njs_eval_error_constructor_init = { - njs_str("EvalError"), njs_eval_error_constructor_properties, njs_nitems(njs_eval_error_constructor_properties), }; @@ -285,7 +283,6 @@ static const njs_object_prop_t njs_inte const njs_object_init_t njs_internal_error_constructor_init = { - njs_str("InternalError"), njs_internal_error_constructor_properties, njs_nitems(njs_internal_error_constructor_properties), }; @@ -327,7 +324,6 @@ static const njs_object_prop_t njs_rang const njs_object_init_t njs_range_error_constructor_init = { - njs_str("RangeError"), njs_range_error_constructor_properties, njs_nitems(njs_range_error_constructor_properties), }; @@ -369,7 +365,6 @@ static const njs_object_prop_t njs_refe const njs_object_init_t njs_reference_error_constructor_init = { - njs_str("ReferenceError"), njs_reference_error_constructor_properties, njs_nitems(njs_reference_error_constructor_properties), }; @@ -411,7 +406,6 @@ static const njs_object_prop_t njs_synt const njs_object_init_t njs_syntax_error_constructor_init = { - njs_str("SyntaxError"), njs_syntax_error_constructor_properties, njs_nitems(njs_syntax_error_constructor_properties), }; @@ -453,7 +447,6 @@ static const njs_object_prop_t njs_type const njs_object_init_t njs_type_error_constructor_init = { - njs_str("TypeError"), njs_type_error_constructor_properties, njs_nitems(njs_type_error_constructor_properties), }; @@ -495,7 +488,6 @@ static const njs_object_prop_t njs_uri_ const njs_object_init_t njs_uri_error_constructor_init = { - njs_str("URIError"), njs_uri_error_constructor_properties, njs_nitems(njs_uri_error_constructor_properties), }; @@ -597,7 +589,6 @@ static const njs_object_prop_t njs_memo const njs_object_init_t njs_memory_error_constructor_init = { - njs_str("MemoryError"), njs_memory_error_constructor_properties, njs_nitems(njs_memory_error_constructor_properties), }; @@ -762,7 +753,6 @@ static const njs_object_prop_t njs_erro const njs_object_init_t njs_error_prototype_init = { - njs_str("Error"), njs_error_prototype_properties, njs_nitems(njs_error_prototype_properties), }; @@ -797,7 +787,6 @@ static const njs_object_prop_t njs_eval const njs_object_init_t njs_eval_error_prototype_init = { - njs_str("EvalError"), njs_eval_error_prototype_properties, njs_nitems(njs_eval_error_prototype_properties), }; @@ -852,7 +841,6 @@ static const njs_object_prop_t njs_inte const njs_object_init_t njs_internal_error_prototype_init = { - njs_str("InternalError"), njs_internal_error_prototype_properties, njs_nitems(njs_internal_error_prototype_properties), }; @@ -887,7 +875,6 @@ static const njs_object_prop_t njs_rang const njs_object_init_t njs_range_error_prototype_init = { - njs_str("RangeError"), njs_range_error_prototype_properties, njs_nitems(njs_range_error_prototype_properties), }; @@ -922,7 +909,6 @@ static const njs_object_prop_t njs_refe const njs_object_init_t njs_reference_error_prototype_init = { - njs_str("ReferenceError"), njs_reference_error_prototype_properties, njs_nitems(njs_reference_error_prototype_properties), }; @@ -957,7 +943,6 @@ static const njs_object_prop_t njs_synt const njs_object_init_t njs_syntax_error_prototype_init = { - njs_str("SyntaxError"), njs_syntax_error_prototype_properties, njs_nitems(njs_syntax_error_prototype_properties), }; @@ -992,7 +977,6 @@ static const njs_object_prop_t njs_type const njs_object_init_t njs_type_error_prototype_init = { - njs_str("TypeError"), njs_type_error_prototype_properties, njs_nitems(njs_type_error_prototype_properties), }; @@ -1027,7 +1011,6 @@ static const njs_object_prop_t njs_uri_ const njs_object_init_t njs_uri_error_prototype_init = { - njs_str("URIError"), njs_uri_error_prototype_properties, njs_nitems(njs_uri_error_prototype_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_fs.c --- a/src/njs_fs.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_fs.c Thu Oct 31 18:17:32 2019 +0300 @@ -1215,7 +1215,6 @@ static const njs_object_prop_t njs_fs_o const njs_object_init_t njs_fs_object_init = { - njs_str("fs"), njs_fs_object_properties, njs_nitems(njs_fs_object_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_function.c --- a/src/njs_function.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_function.c Thu Oct 31 18:17:32 2019 +0300 @@ -275,7 +275,6 @@ const njs_object_prop_t njs_arguments_o const njs_object_init_t njs_arguments_object_instance_init = { - njs_str("Argument object instance"), njs_arguments_object_instance_properties, njs_nitems(njs_arguments_object_instance_properties), }; @@ -872,7 +871,6 @@ static const njs_object_prop_t njs_func const njs_object_init_t njs_function_constructor_init = { - njs_str("Function"), njs_function_constructor_properties, njs_nitems(njs_function_constructor_properties), }; @@ -1157,7 +1155,6 @@ static const njs_object_prop_t njs_func const njs_object_init_t njs_function_prototype_init = { - njs_str("Function"), njs_function_prototype_properties, njs_nitems(njs_function_prototype_properties), }; @@ -1182,7 +1179,6 @@ const njs_object_prop_t njs_function_in const njs_object_init_t njs_function_instance_init = { - njs_str("Function instance"), njs_function_instance_properties, njs_nitems(njs_function_instance_properties), }; @@ -1200,7 +1196,6 @@ const njs_object_prop_t njs_arrow_insta const njs_object_init_t njs_arrow_instance_init = { - njs_str("Arrow instance"), njs_arrow_instance_properties, njs_nitems(njs_arrow_instance_properties), }; @@ -1237,7 +1232,6 @@ static const njs_object_prop_t njs_eval const njs_object_init_t njs_eval_function_init = { - njs_str("eval"), njs_eval_function_properties, njs_nitems(njs_eval_function_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_json.c --- a/src/njs_json.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_json.c Thu Oct 31 18:17:32 2019 +0300 @@ -2122,7 +2122,6 @@ static const njs_object_prop_t njs_json const njs_object_init_t njs_json_object_init = { - njs_str("JSON"), njs_json_object_properties, njs_nitems(njs_json_object_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_math.c --- a/src/njs_math.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_math.c Thu Oct 31 18:17:32 2019 +0300 @@ -1321,7 +1321,6 @@ static const njs_object_prop_t njs_math const njs_object_init_t njs_math_object_init = { - njs_str("Math"), njs_math_object_properties, njs_nitems(njs_math_object_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_number.c --- a/src/njs_number.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_number.c Thu Oct 31 18:17:32 2019 +0300 @@ -499,7 +499,6 @@ static const njs_object_prop_t njs_numb const njs_object_init_t njs_number_constructor_init = { - njs_str("Number"), njs_number_constructor_properties, njs_nitems(njs_number_constructor_properties), }; @@ -963,7 +962,6 @@ static const njs_object_prop_t njs_numb const njs_object_init_t njs_number_prototype_init = { - njs_str("Number"), njs_number_prototype_properties, njs_nitems(njs_number_prototype_properties), }; @@ -1146,7 +1144,6 @@ static const njs_object_prop_t njs_is_f const njs_object_init_t njs_is_finite_function_init = { - njs_str("isFinite"), njs_is_finite_function_properties, njs_nitems(njs_is_finite_function_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_object.c --- a/src/njs_object.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object.c Thu Oct 31 18:17:32 2019 +0300 @@ -1912,7 +1912,6 @@ static const njs_object_prop_t njs_obje const njs_object_init_t njs_object_constructor_init = { - njs_str("Object"), njs_object_constructor_properties, njs_nitems(njs_object_constructor_properties), }; @@ -2368,7 +2367,6 @@ static const njs_object_prop_t njs_obje const njs_object_init_t njs_object_prototype_init = { - njs_str("Object"), njs_object_prototype_properties, njs_nitems(njs_object_prototype_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_object.h --- a/src/njs_object.h Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_object.h Thu Oct 31 18:17:32 2019 +0300 @@ -37,7 +37,6 @@ typedef enum { struct njs_object_init_s { - njs_str_t name; const njs_object_prop_t *properties; njs_uint_t items; }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_regexp.c --- a/src/njs_regexp.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_regexp.c Thu Oct 31 18:17:32 2019 +0300 @@ -1189,7 +1189,6 @@ static const njs_object_prop_t njs_rege const njs_object_init_t njs_regexp_constructor_init = { - njs_str("RegExp"), njs_regexp_constructor_properties, njs_nitems(njs_regexp_constructor_properties), }; @@ -1266,7 +1265,6 @@ static const njs_object_prop_t njs_rege const njs_object_init_t njs_regexp_prototype_init = { - njs_str("RegExp"), njs_regexp_prototype_properties, njs_nitems(njs_regexp_prototype_properties), }; diff -r 2868545c461b -r ce17b8cd9630 src/njs_shell.c --- a/src/njs_shell.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_shell.c Thu Oct 31 18:17:32 2019 +0300 @@ -85,8 +85,6 @@ static njs_int_t njs_ext_console_log(njs njs_uint_t nargs, njs_index_t unused); static njs_int_t njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); -static njs_int_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); static njs_int_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); static njs_int_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, @@ -126,17 +124,6 @@ static njs_external_t njs_ext_console[] njs_ext_console_dump, 0 }, - { njs_str("help"), - NJS_EXTERN_METHOD, - NULL, - 0, - NULL, - NULL, - NULL, - NULL, - njs_ext_console_help, - 0 }, - { njs_str("time"), NJS_EXTERN_METHOD, NULL, @@ -473,8 +460,7 @@ njs_interactive_shell(njs_opts_t *opts, if (!opts->quiet) { njs_printf("interactive njs %s\n\n", NJS_VERSION); - njs_printf("v. -> the properties and prototype methods of v.\n"); - njs_printf("type console.help() for more information\n\n"); + njs_printf("v. -> the properties and prototype methods of v.\n\n"); } for ( ;; ) { @@ -1025,37 +1011,6 @@ njs_ext_console_dump(njs_vm_t *vm, njs_v static njs_int_t -njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused) -{ - const njs_object_init_t *obj, **objpp; - - njs_printf("VM built-in objects:\n"); - - for (objpp = njs_constructor_init; *objpp != NULL; objpp++) { - obj = *objpp; - - njs_printf(" %V\n", &obj->name); - } - - for (objpp = njs_object_init; *objpp != NULL; objpp++) { - obj = *objpp; - - njs_printf(" %V\n", &obj->name); - } - - njs_printf("\nEmbedded objects:\n"); - njs_printf(" console\n"); - - njs_printf("\n"); - - njs_set_undefined(&vm->retval); - - return NJS_OK; -} - - -static njs_int_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { diff -r 2868545c461b -r ce17b8cd9630 src/njs_string.c --- a/src/njs_string.c Thu Oct 31 18:17:31 2019 +0300 +++ b/src/njs_string.c Thu Oct 31 18:17:32 2019 +0300 @@ -630,7 +630,6 @@ static const njs_object_prop_t njs_stri const njs_object_init_t njs_string_constructor_init = { - njs_str("String"), njs_string_constructor_properties, njs_nitems(njs_string_constructor_properties), }; @@ -4723,7 +4722,6 @@ static const njs_object_prop_t njs_stri const njs_object_init_t njs_string_prototype_init = { - njs_str("String"), njs_string_prototype_properties, njs_nitems(njs_string_prototype_properties), }; @@ -4740,7 +4738,6 @@ const njs_object_prop_t njs_string_inst const njs_object_init_t njs_string_instance_init = { - njs_str("String instance"), njs_string_instance_properties, njs_nitems(njs_string_instance_properties), }; diff -r 2868545c461b -r ce17b8cd9630 test/njs_expect_test.exp --- a/test/njs_expect_test.exp Thu Oct 31 18:17:31 2019 +0300 +++ b/test/njs_expect_test.exp Thu Oct 31 18:17:32 2019 +0300 @@ -26,7 +26,6 @@ proc njs_test {body {opts ""}} { expect -re "interactive njs \\d+\.\\d+\.\\d+\r\n\r" expect "v. -> the properties and prototype methods of v.\r -type console.help() for more information\r \r >> " @@ -220,8 +219,6 @@ njs_test { "console.dump(1)\r\n1\r\nundefined\r\n>> "} {"console.dump(1, 'a')\r\n" "console.dump(1, 'a')\r\n1 a\r\nundefined\r\n>> "} - {"console.help()\r\n" - "console.help()\r\nVM built-in objects:"} } # console.time* functions From xeioex at nginx.com Thu Oct 31 15:18:04 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:04 +0000 Subject: [njs] Fixed "constructor" property of "Hash" and "Hmac" objects. Message-ID: details: https://hg.nginx.org/njs/rev/297f7dd356c0 branches: changeset: 1215:297f7dd356c0 user: Dmitry Volyntsev date: Thu Oct 31 18:17:34 2019 +0300 description: Fixed "constructor" property of "Hash" and "Hmac" objects. diffstat: src/njs_crypto.c | 16 ++++++++++++++++ src/test/njs_unit_test.c | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 0 deletions(-) diffs (68 lines): diff -r 5abe92b2cfd0 -r 297f7dd356c0 src/njs_crypto.c --- a/src/njs_crypto.c Thu Oct 31 18:17:33 2019 +0300 +++ b/src/njs_crypto.c Thu Oct 31 18:17:34 2019 +0300 @@ -343,6 +343,14 @@ static const njs_object_prop_t njs_hash .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("constructor"), + .value = njs_prop_handler(njs_object_prototype_create_constructor), + .writable = 1, + .configurable = 1, + }, }; @@ -634,6 +642,14 @@ static const njs_object_prop_t njs_hmac .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("constructor"), + .value = njs_prop_handler(njs_object_prototype_create_constructor), + .writable = 1, + .configurable = 1, + }, }; diff -r 5abe92b2cfd0 -r 297f7dd356c0 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Oct 31 18:17:33 2019 +0300 +++ b/src/test/njs_unit_test.c Thu Oct 31 18:17:34 2019 +0300 @@ -14191,6 +14191,15 @@ static njs_unit_test_t njs_test[] = { njs_str("Object.prototype.toString.call(require('crypto').createHash('sha1'))"), njs_str("[object Object]") }, + { njs_str("var h = require('crypto').createHash('sha1');" + "var Hash = h.constructor; " + "Hash('sha1').update('AB').digest('hex')"), + njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") }, + + { njs_str("var h = require('crypto').createHash('sha1');" + "h.constructor.name"), + njs_str("Hash") }, + { njs_str("var h = require('crypto').createHash('md5');" "h.update('AB').digest('hex')"), njs_str("b86fc6b051f63d73de262d4c34e3a0a9") }, @@ -14284,6 +14293,15 @@ static njs_unit_test_t njs_test[] = "h.digest().toString('hex')"), njs_str("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") }, + { njs_str("var h = require('crypto').createHmac('sha1', '');" + "var Hmac = h.constructor; " + "Hmac('sha1', '').digest('hex')"), + njs_str("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") }, + + { njs_str("var h = require('crypto').createHmac('sha1', '');" + "h.constructor.name"), + njs_str("Hmac") }, + { njs_str("var h = require('crypto').createHmac('md5', 'secret key');" "h.update('AB').digest('hex')"), njs_str("9c72728915eb26620a5caeafd0063b29") }, From xeioex at nginx.com Thu Oct 31 15:18:04 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 31 Oct 2019 15:18:04 +0000 Subject: [njs] Refactored object type initialization. Message-ID: details: https://hg.nginx.org/njs/rev/5abe92b2cfd0 branches: changeset: 1214:5abe92b2cfd0 user: Dmitry Volyntsev date: Thu Oct 31 18:17:33 2019 +0300 description: Refactored object type initialization. diffstat: src/njs_array.c | 10 +- src/njs_array.h | 6 +- src/njs_boolean.c | 11 +- src/njs_boolean.h | 6 +- src/njs_builtin.c | 288 +++++++++------------------------------------------- src/njs_builtin.h | 17 --- src/njs_crypto.c | 22 +++- src/njs_crypto.h | 12 +- src/njs_date.c | 10 +- src/njs_date.h | 6 +- src/njs_error.c | 90 ++++++++++++++- src/njs_error.h | 46 +------ src/njs_fs.h | 1 + src/njs_function.c | 35 ++--- src/njs_function.h | 13 +- src/njs_main.h | 1 - src/njs_number.c | 32 +---- src/njs_number.h | 5 +- src/njs_object.c | 10 +- src/njs_object.h | 5 +- src/njs_regexp.c | 10 +- src/njs_regexp.h | 6 +- src/njs_string.c | 11 +- src/njs_string.h | 5 +- src/njs_value.h | 8 + src/njs_vm.h | 2 + 26 files changed, 265 insertions(+), 403 deletions(-) diffs (truncated from 1251 to 1000 lines): diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_array.c --- a/src/njs_array.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_array.c Thu Oct 31 18:17:33 2019 +0300 @@ -177,7 +177,7 @@ memory_error: } -njs_int_t +static njs_int_t njs_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -3006,3 +3006,11 @@ const njs_object_init_t njs_array_insta njs_array_instance_properties, njs_nitems(njs_array_instance_properties), }; + + +const njs_object_type_init_t njs_array_type_init = { + .constructor = njs_array_constructor, + .prototype_props = &njs_array_prototype_init, + .constructor_props = &njs_array_constructor_init, + .value = { .object = { .type = NJS_ARRAY } }, +}; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_array.h --- a/src/njs_array.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_array.h Thu Oct 31 18:17:33 2019 +0300 @@ -21,12 +21,10 @@ njs_int_t njs_array_string_add(njs_vm_t const u_char *start, size_t size, size_t length); njs_int_t njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t append); -njs_int_t njs_array_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); + -extern const njs_object_init_t njs_array_constructor_init; -extern const njs_object_init_t njs_array_prototype_init; extern const njs_object_init_t njs_array_instance_init; +extern const njs_object_type_init_t njs_array_type_init; #endif /* _NJS_ARRAY_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_boolean.c --- a/src/njs_boolean.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_boolean.c Thu Oct 31 18:17:33 2019 +0300 @@ -8,7 +8,7 @@ #include -njs_int_t +static njs_int_t njs_boolean_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -163,3 +163,12 @@ const njs_object_init_t njs_boolean_pro njs_boolean_prototype_properties, njs_nitems(njs_boolean_prototype_properties), }; + + +const njs_object_type_init_t njs_boolean_type_init = { + .constructor = njs_boolean_constructor, + .prototype_props = &njs_boolean_prototype_init, + .constructor_props = &njs_boolean_constructor_init, + .value = { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), + .object = { .type = NJS_OBJECT_BOOLEAN } } }, +}; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_boolean.h --- a/src/njs_boolean.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_boolean.h Thu Oct 31 18:17:33 2019 +0300 @@ -8,11 +8,7 @@ #define _NJS_BOOLEAN_H_INCLUDED_ -njs_int_t njs_boolean_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); - -extern const njs_object_init_t njs_boolean_constructor_init; -extern const njs_object_init_t njs_boolean_prototype_init; +extern const njs_object_type_init_t njs_boolean_type_init; #endif /* _NJS_BOOLEAN_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_builtin.c --- a/src/njs_builtin.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_builtin.c Thu Oct 31 18:17:33 2019 +0300 @@ -10,11 +10,6 @@ typedef struct { - njs_function_native_t native; -} njs_function_init_t; - - -typedef struct { enum { NJS_BUILTIN_TRAVERSE_KEYS, NJS_BUILTIN_TRAVERSE_MATCH, @@ -27,8 +22,6 @@ typedef struct { } njs_builtin_traverse_t; -static njs_int_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); static njs_arr_t *njs_vm_expression_completions(njs_vm_t *vm, njs_str_t *expression); static njs_arr_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object); @@ -36,12 +29,12 @@ static njs_int_t njs_env_hash_init(njs_v char **environment); -const njs_object_init_t njs_global_this_init; -const njs_object_init_t njs_njs_object_init; -const njs_object_init_t njs_process_object_init; +static const njs_object_init_t njs_global_this_init; +static const njs_object_init_t njs_njs_object_init; +static const njs_object_init_t njs_process_object_init; -const njs_object_init_t *njs_object_init[] = { +static const njs_object_init_t *njs_object_init[] = { &njs_global_this_init, &njs_njs_object_init, &njs_process_object_init, @@ -51,129 +44,43 @@ const njs_object_init_t *njs_object_ini }; -const njs_object_init_t *njs_module_init[] = { +static const njs_object_init_t *njs_module_init[] = { &njs_fs_object_init, &njs_crypto_object_init, NULL }; -const njs_object_init_t *njs_prototype_init[] = { - &njs_object_prototype_init, - &njs_array_prototype_init, - &njs_boolean_prototype_init, - &njs_number_prototype_init, - &njs_string_prototype_init, - &njs_function_prototype_init, - &njs_regexp_prototype_init, - &njs_date_prototype_init, - &njs_hash_prototype_init, - &njs_hmac_prototype_init, - &njs_error_prototype_init, - &njs_eval_error_prototype_init, - &njs_internal_error_prototype_init, - &njs_range_error_prototype_init, - &njs_reference_error_prototype_init, - &njs_syntax_error_prototype_init, - &njs_type_error_prototype_init, - &njs_uri_error_prototype_init, - &njs_internal_error_prototype_init, - NULL -}; - +static const njs_object_type_init_t *const + njs_object_type_init[NJS_OBJ_TYPE_MAX] = +{ + /* Global types. */ -const njs_object_init_t *njs_constructor_init[] = { - &njs_object_constructor_init, - &njs_array_constructor_init, - &njs_boolean_constructor_init, - &njs_number_constructor_init, - &njs_string_constructor_init, - &njs_function_constructor_init, - &njs_regexp_constructor_init, - &njs_date_constructor_init, - &njs_hash_constructor_init, - &njs_hmac_constructor_init, - &njs_error_constructor_init, - &njs_eval_error_constructor_init, - &njs_internal_error_constructor_init, - &njs_range_error_constructor_init, - &njs_reference_error_constructor_init, - &njs_syntax_error_constructor_init, - &njs_type_error_constructor_init, - &njs_uri_error_constructor_init, - &njs_memory_error_constructor_init, - NULL -}; - + &njs_obj_type_init, + &njs_array_type_init, + &njs_boolean_type_init, + &njs_number_type_init, + &njs_string_type_init, + &njs_function_type_init, + &njs_regexp_type_init, + &njs_date_type_init, -const njs_function_init_t njs_native_constructors[] = { - /* SunC does not allow empty array initialization. */ - { njs_object_constructor }, - { njs_array_constructor }, - { njs_boolean_constructor }, - { njs_number_constructor }, - { njs_string_constructor }, - { njs_function_constructor}, - { njs_regexp_constructor }, - { njs_date_constructor }, - { njs_hash_constructor }, - { njs_hmac_constructor }, - { njs_error_constructor }, - { njs_eval_error_constructor }, - { njs_internal_error_constructor }, - { njs_range_error_constructor }, - { njs_reference_error_constructor }, - { njs_syntax_error_constructor }, - { njs_type_error_constructor }, - { njs_uri_error_constructor }, - { njs_memory_error_constructor }, -}; + /* Hidden types. */ + &njs_hash_type_init, + &njs_hmac_type_init, -const njs_object_prototype_t njs_prototype_values[] = { - /* - * GCC 4 complains about uninitialized .shared field, - * if the .type field is initialized as .object.type. - */ - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_ARRAY } }, + /* Error types. */ - /* - * The .object.type field must be initialzed after the .value field, - * otherwise SunC 5.9 treats the .value as .object.value or so. - */ - { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), - .object = { .type = NJS_OBJECT_BOOLEAN } } }, - - { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), - .object = { .type = NJS_OBJECT_NUMBER } } }, - - { .object_value = { .value = njs_string(""), - .object = { .type = NJS_OBJECT_STRING } } }, - - { .function = { .native = 1, - .args_offset = 1, - .u.native = njs_prototype_function, - .object = { .type = NJS_FUNCTION } } }, - - { .object = { .type = NJS_REGEXP } }, - - { .object = { .type = NJS_OBJECT } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_OBJECT } }, + &njs_error_type_init, + &njs_eval_error_type_init, + &njs_internal_error_type_init, + &njs_range_error_type_init, + &njs_reference_error_type_init, + &njs_syntax_error_type_init, + &njs_type_error_type_init, + &njs_uri_error_type_init, + &njs_memory_error_type_init, }; @@ -192,16 +99,16 @@ njs_int_t njs_builtin_objects_create(njs_vm_t *vm) { njs_int_t ret; + njs_uint_t i; njs_module_t *module; njs_object_t *object, *string_object; - njs_function_t *func; + njs_function_t *constructor; njs_vm_shared_t *shared; njs_lvlhsh_query_t lhq; njs_regexp_pattern_t *pattern; njs_object_prototype_t *prototype; const njs_object_prop_t *prop; const njs_object_init_t *obj, **p; - const njs_function_init_t *f; static const njs_str_t sandbox_key = njs_str("sandbox"); static const njs_str_t name_key = njs_str("name"); @@ -336,19 +243,17 @@ njs_builtin_objects_create(njs_vm_t *vm) } prototype = shared->prototypes; - memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); - for (p = njs_prototype_init; *p != NULL; p++) { - obj = *p; + for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { + prototype[i] = njs_object_type_init[i]->value; - ret = njs_object_hash_init(vm, &prototype->object.shared_hash, obj); + ret = njs_object_hash_init(vm, &prototype[i].object.shared_hash, + njs_object_type_init[i]->prototype_props); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } - prototype->object.extensible = 1; - - prototype++; + prototype[i].object.extensible = 1; } shared->prototypes[NJS_OBJ_TYPE_REGEXP].regexp.pattern = @@ -361,28 +266,23 @@ njs_builtin_objects_create(njs_vm_t *vm) string_object->shared = 1; string_object->extensible = 0; - f = njs_native_constructors; - func = shared->constructors; - - for (p = njs_constructor_init; *p != NULL; p++) { - obj = *p; + constructor = shared->constructors; - func->object.type = NJS_FUNCTION; - func->object.shared = 0; - func->object.extensible = 1; - func->native = 1; - func->ctor = 1; - func->args_offset = 1; + for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { + constructor[i].object.type = NJS_FUNCTION; + constructor[i].object.shared = 0; + constructor[i].object.extensible = 1; + constructor[i].native = 1; + constructor[i].ctor = 1; + constructor[i].args_offset = 1; - func->u.native = f->native; + constructor[i].u.native = njs_object_type_init[i]->constructor; - ret = njs_object_hash_init(vm, &func->object.shared_hash, obj); + ret = njs_object_hash_init(vm, &constructor[i].object.shared_hash, + njs_object_type_init[i]->constructor_props); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } - - f++; - func++; } vm->shared = shared; @@ -391,90 +291,6 @@ njs_builtin_objects_create(njs_vm_t *vm) } -static njs_int_t -njs_prototype_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused) -{ - njs_set_undefined(&vm->retval); - - return NJS_OK; -} - - -/* - * Object(), - * Object.__proto__ -> Function.prototype, - * Object.prototype.__proto__ -> null, - * the null value is handled by njs_object_prototype_proto(), - * - * Array(), - * Array.__proto__ -> Function.prototype, - * Array.prototype.__proto__ -> Object.prototype, - * - * Boolean(), - * Boolean.__proto__ -> Function.prototype, - * Boolean.prototype.__proto__ -> Object.prototype, - * - * Number(), - * Number.__proto__ -> Function.prototype, - * Number.prototype.__proto__ -> Object.prototype, - * - * String(), - * String.__proto__ -> Function.prototype, - * String.prototype.__proto__ -> Object.prototype, - * - * Function(), - * Function.__proto__ -> Function.prototype, - * Function.prototype.__proto__ -> Object.prototype, - * - * RegExp(), - * RegExp.__proto__ -> Function.prototype, - * RegExp.prototype.__proto__ -> Object.prototype, - * - * Date(), - * Date.__proto__ -> Function.prototype, - * Date.prototype.__proto__ -> Object.prototype, - * - * Error(), - * Error.__proto__ -> Function.prototype, - * Error.prototype.__proto__ -> Object.prototype, - * - * EvalError(), - * EvalError.__proto__ -> Error, - * EvalError.prototype.__proto__ -> Error.prototype, - * - * InternalError(), - * InternalError.__proto__ -> Error, - * InternalError.prototype.__proto__ -> Error.prototype, - * - * RangeError(), - * RangeError.__proto__ -> Error, - * RangeError.prototype.__proto__ -> Error.prototype, - * - * ReferenceError(), - * ReferenceError.__proto__ -> Error, - * ReferenceError.prototype.__proto__ -> Error.prototype, - * - * SyntaxError(), - * SyntaxError.__proto__ -> Error, - * SyntaxError.prototype.__proto__ -> Error.prototype, - * - * TypeError(), - * TypeError.__proto__ -> Error, - * TypeError.prototype.__proto__ -> Error.prototype, - * - * URIError(), - * URIError.__proto__ -> Error, - * URIError.prototype.__proto__ -> Error.prototype, - * - * MemoryError(), - * MemoryError.__proto__ -> Error, - * MemoryError.prototype.__proto__ -> Error.prototype, - * - * eval(), - * eval.__proto__ -> Function.prototype. - */ - njs_int_t njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global) { @@ -972,7 +788,7 @@ njs_builtin_match_native_function(njs_vm /* Constructor from built-in modules (not-mapped to global object). */ - for (i = NJS_OBJ_TYPE_CRYPTO_HASH; i < NJS_OBJ_TYPE_ERROR; i++) { + for (i = NJS_OBJ_TYPE_HIDDEN_MIN; i < NJS_OBJ_TYPE_HIDDEN_MAX; i++) { njs_set_object(&value, &vm->constructors[i].object); ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name), @@ -1475,7 +1291,7 @@ static const njs_object_prop_t njs_glob }; -const njs_object_init_t njs_global_this_init = { +static const njs_object_init_t njs_global_this_init = { njs_global_this_object_properties, njs_nitems(njs_global_this_object_properties) }; @@ -1500,7 +1316,7 @@ static const njs_object_prop_t njs_njs_ }; -const njs_object_init_t njs_njs_object_init = { +static const njs_object_init_t njs_njs_object_init = { njs_njs_object_properties, njs_nitems(njs_njs_object_properties), }; @@ -1708,7 +1524,7 @@ static const njs_object_prop_t njs_proc }; -const njs_object_init_t njs_process_object_init = { +static const njs_object_init_t njs_process_object_init = { njs_process_object_properties, njs_nitems(njs_process_object_properties), }; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_builtin.h --- a/src/njs_builtin.h Thu Oct 31 18:17:32 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NJS_BUILTIN_H_INCLUDED_ -#define _NJS_BUILTIN_H_INCLUDED_ - - -extern const njs_object_init_t *njs_object_init[]; -extern const njs_object_init_t *njs_module_init[]; -extern const njs_object_init_t *njs_prototype_init[]; -extern const njs_object_init_t *njs_constructor_init[]; - - -#endif /* _NJS_BUILTIN_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_crypto.c --- a/src/njs_crypto.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_crypto.c Thu Oct 31 18:17:33 2019 +0300 @@ -352,7 +352,7 @@ const njs_object_init_t njs_hash_protot }; -njs_int_t +static njs_int_t njs_hash_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -390,6 +390,15 @@ const njs_object_init_t njs_hash_constr }; +const njs_object_type_init_t njs_hash_type_init = { + .constructor = njs_hash_constructor, + .prototype_props = &njs_hash_prototype_init, + .constructor_props = &njs_hash_constructor_init, + .value = { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, +}; + + static njs_int_t njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) @@ -634,7 +643,7 @@ const njs_object_init_t njs_hmac_protot }; -njs_int_t +static njs_int_t njs_hmac_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -712,6 +721,15 @@ const njs_object_init_t njs_crypto_obje }; +const njs_object_type_init_t njs_hmac_type_init = { + .constructor = njs_hmac_constructor, + .prototype_props = &njs_hmac_prototype_init, + .constructor_props = &njs_hmac_constructor_init, + .value = { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, +}; + + static njs_hash_alg_t * njs_crypto_alg(njs_vm_t *vm, const njs_str_t *name) { diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_crypto.h --- a/src/njs_crypto.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_crypto.h Thu Oct 31 18:17:33 2019 +0300 @@ -7,18 +7,10 @@ #ifndef _NJS_CRYPTO_H_INCLUDED_ #define _NJS_CRYPTO_H_INCLUDED_ -njs_int_t njs_hash_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_hmac_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); - extern const njs_object_init_t njs_crypto_object_init; -extern const njs_object_init_t njs_hash_prototype_init; -extern const njs_object_init_t njs_hmac_prototype_init; - -extern const njs_object_init_t njs_hash_constructor_init; -extern const njs_object_init_t njs_hmac_constructor_init; +extern const njs_object_type_init_t njs_hash_type_init; +extern const njs_object_type_init_t njs_hmac_type_init; #endif /* _NJS_CRYPTO_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_date.c --- a/src/njs_date.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_date.c Thu Oct 31 18:17:33 2019 +0300 @@ -168,7 +168,7 @@ njs_make_date(int64_t days, int64_t time } -njs_int_t +static njs_int_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -2890,3 +2890,11 @@ const njs_object_init_t njs_date_protot njs_date_prototype_properties, njs_nitems(njs_date_prototype_properties), }; + + +const njs_object_type_init_t njs_date_type_init = { + .constructor = njs_date_constructor, + .prototype_props = &njs_date_prototype_init, + .constructor_props = &njs_date_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_date.h --- a/src/njs_date.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_date.h Thu Oct 31 18:17:33 2019 +0300 @@ -8,15 +8,11 @@ #define _NJS_DATE_H_INCLUDED_ -njs_int_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); - njs_int_t njs_date_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *date); -extern const njs_object_init_t njs_date_constructor_init; -extern const njs_object_init_t njs_date_prototype_init; +extern const njs_object_type_init_t njs_date_type_init; #endif /* _NJS_DATE_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_error.c --- a/src/njs_error.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_error.c Thu Oct 31 18:17:33 2019 +0300 @@ -165,7 +165,7 @@ njs_error_create(njs_vm_t *vm, njs_value } -njs_int_t +static njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -206,7 +206,7 @@ const njs_object_init_t njs_error_const }; -njs_int_t +static njs_int_t njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -247,7 +247,7 @@ const njs_object_init_t njs_eval_error_ }; -njs_int_t +static njs_int_t njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -288,7 +288,7 @@ const njs_object_init_t njs_internal_er }; -njs_int_t +static njs_int_t njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -329,7 +329,7 @@ const njs_object_init_t njs_range_error }; -njs_int_t +static njs_int_t njs_reference_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -370,7 +370,7 @@ const njs_object_init_t njs_reference_e }; -njs_int_t +static njs_int_t njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -411,7 +411,7 @@ const njs_object_init_t njs_syntax_erro }; -njs_int_t +static njs_int_t njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -452,7 +452,7 @@ const njs_object_init_t njs_type_error_ }; -njs_int_t +static njs_int_t njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -526,7 +526,7 @@ njs_memory_error(njs_vm_t *vm) } -njs_int_t +static njs_int_t njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -758,6 +758,14 @@ const njs_object_init_t njs_error_proto }; +const njs_object_type_init_t njs_error_type_init = { + .constructor = njs_error_constructor, + .prototype_props = &njs_error_prototype_init, + .constructor_props = &njs_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_eval_error_prototype_properties[] = { { @@ -792,6 +800,14 @@ const njs_object_init_t njs_eval_error_ }; +const njs_object_type_init_t njs_eval_error_type_init = { + .constructor = njs_eval_error_constructor, + .prototype_props = &njs_eval_error_prototype_init, + .constructor_props = &njs_eval_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static njs_int_t njs_internal_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) @@ -846,6 +862,22 @@ const njs_object_init_t njs_internal_er }; +const njs_object_type_init_t njs_internal_error_type_init = { + .constructor = njs_internal_error_constructor, + .prototype_props = &njs_internal_error_prototype_init, + .constructor_props = &njs_internal_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + +const njs_object_type_init_t njs_memory_error_type_init = { + .constructor = njs_memory_error_constructor, + .prototype_props = &njs_internal_error_prototype_init, + .constructor_props = &njs_memory_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_range_error_prototype_properties[] = { { @@ -880,6 +912,14 @@ const njs_object_init_t njs_range_error }; +const njs_object_type_init_t njs_range_error_type_init = { + .constructor = njs_range_error_constructor, + .prototype_props = &njs_range_error_prototype_init, + .constructor_props = &njs_range_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_reference_error_prototype_properties[] = { { @@ -914,6 +954,14 @@ const njs_object_init_t njs_reference_e }; +const njs_object_type_init_t njs_reference_error_type_init = { + .constructor = njs_reference_error_constructor, + .prototype_props = &njs_reference_error_prototype_init, + .constructor_props = &njs_reference_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_syntax_error_prototype_properties[] = { { @@ -948,6 +996,14 @@ const njs_object_init_t njs_syntax_erro }; +const njs_object_type_init_t njs_syntax_error_type_init = { + .constructor = njs_syntax_error_constructor, + .prototype_props = &njs_syntax_error_prototype_init, + .constructor_props = &njs_syntax_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_type_error_prototype_properties[] = { { @@ -982,6 +1038,14 @@ const njs_object_init_t njs_type_error_ }; +const njs_object_type_init_t njs_type_error_type_init = { + .constructor = njs_type_error_constructor, + .prototype_props = &njs_type_error_prototype_init, + .constructor_props = &njs_type_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_uri_error_prototype_properties[] = { { @@ -1014,3 +1078,11 @@ const njs_object_init_t njs_uri_error_p njs_uri_error_prototype_properties, njs_nitems(njs_uri_error_prototype_properties), }; + + +const njs_object_type_init_t njs_uri_error_type_init = { + .constructor = njs_uri_error_constructor, + .prototype_props = &njs_uri_error_prototype_init, + .constructor_props = &njs_uri_error_constructor_init, + .value = { .object = { .type = NJS_OBJECT } }, +}; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_error.h --- a/src/njs_error.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_error.h Thu Oct 31 18:17:33 2019 +0300 @@ -42,47 +42,19 @@ void njs_memory_error_set(njs_vm_t *vm, njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name, const njs_value_t *message); -njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_reference_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); -njs_int_t njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); - njs_int_t njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error); -extern const njs_object_init_t njs_error_constructor_init; -extern const njs_object_init_t njs_eval_error_constructor_init; -extern const njs_object_init_t njs_internal_error_constructor_init; -extern const njs_object_init_t njs_range_error_constructor_init; -extern const njs_object_init_t njs_reference_error_constructor_init; -extern const njs_object_init_t njs_syntax_error_constructor_init; -extern const njs_object_init_t njs_type_error_constructor_init; -extern const njs_object_init_t njs_uri_error_constructor_init; -extern const njs_object_init_t njs_memory_error_constructor_init; - -extern const njs_object_init_t njs_error_prototype_init; -extern const njs_object_init_t njs_eval_error_prototype_init; -extern const njs_object_init_t njs_internal_error_prototype_init; -extern const njs_object_init_t njs_range_error_prototype_init; -extern const njs_object_init_t njs_reference_error_prototype_init; -extern const njs_object_init_t njs_syntax_error_prototype_init; -extern const njs_object_init_t njs_type_error_prototype_init; -extern const njs_object_init_t njs_uri_error_prototype_init; +extern const njs_object_type_init_t njs_error_type_init; +extern const njs_object_type_init_t njs_eval_error_type_init; +extern const njs_object_type_init_t njs_internal_error_type_init; +extern const njs_object_type_init_t njs_range_error_type_init; +extern const njs_object_type_init_t njs_reference_error_type_init; +extern const njs_object_type_init_t njs_syntax_error_type_init; +extern const njs_object_type_init_t njs_type_error_type_init; +extern const njs_object_type_init_t njs_uri_error_type_init; +extern const njs_object_type_init_t njs_memory_error_type_init; #endif /* _NJS_BOOLEAN_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_fs.h --- a/src/njs_fs.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_fs.h Thu Oct 31 18:17:33 2019 +0300 @@ -7,6 +7,7 @@ #ifndef _NJS_FS_H_INCLUDED_ #define _NJS_FS_H_INCLUDED_ + extern const njs_object_init_t njs_fs_object_init; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_function.c --- a/src/njs_function.c Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_function.c Thu Oct 31 18:17:33 2019 +0300 @@ -723,7 +723,7 @@ njs_function_prototype_create(njs_vm_t * } -njs_int_t +static njs_int_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { @@ -1211,27 +1211,22 @@ njs_eval_function(njs_vm_t *vm, njs_valu } -static const njs_object_prop_t njs_eval_function_properties[] = +static njs_int_t +njs_prototype_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused) { - /* eval.name == "eval". */ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("eval"), - .configurable = 1, - }, + njs_set_undefined(&vm->retval); - /* eval.length == 1. */ - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 1.0), - .configurable = 1, - }, -}; + return NJS_OK; +} -const njs_object_init_t njs_eval_function_init = { - njs_eval_function_properties, - njs_nitems(njs_eval_function_properties), +const njs_object_type_init_t njs_function_type_init = { + .constructor = njs_function_constructor, + .prototype_props = &njs_function_prototype_init, + .constructor_props = &njs_function_constructor_init, + .value = { .function = { .native = 1, + .args_offset = 1, + .u.native = njs_prototype_function, + .object = { .type = NJS_FUNCTION } } }, }; diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_function.h --- a/src/njs_function.h Thu Oct 31 18:17:32 2019 +0300 +++ b/src/njs_function.h Thu Oct 31 18:17:33 2019 +0300 @@ -107,8 +107,8 @@ njs_int_t njs_function_rest_parameters_i njs_native_frame_t *frame); njs_int_t njs_function_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval); -njs_int_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused); +njs_int_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused); njs_int_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs, njs_bool_t ctor); @@ -194,16 +194,9 @@ njs_function_apply(njs_vm_t *vm, njs_fun } -extern const njs_object_init_t njs_function_constructor_init; -extern const njs_object_init_t njs_function_prototype_init; +extern const njs_object_type_init_t njs_function_type_init; extern const njs_object_init_t njs_function_instance_init; extern const njs_object_init_t njs_arrow_instance_init; extern const njs_object_init_t njs_arguments_object_instance_init; -njs_int_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused); - -extern const njs_object_init_t njs_eval_function_init; - - #endif /* _NJS_FUNCTION_H_INCLUDED_ */ diff -r ce17b8cd9630 -r 5abe92b2cfd0 src/njs_main.h