You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by GitBox <gi...@apache.org> on 2020/04/15 00:33:14 UTC

[GitHub] [couchdb] wohali opened a new pull request #2788: SpiderMonkey 68 support

wohali opened a new pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788
 
 
   ## Overview
   
   PR is WIP, pending additional changes from #2786 when it's ready to go.
   
   Also, global `s/,/.` on the `rebar.config.script` files I touched. That part is pre-approved by @rnewson .
   
   ## Testing recommendations
   
   Set up a dev environment under Ubuntu 20.04 (Focal Fossa), then `make check`.
   
   ## Related Issues or Pull Requests
   
   Fixes #2770 .
   
   ## Checklist
   
   - [X] Code is written and works correctly
   - [X] Changes are covered by tests
   - [ ] A PR for documentation changes has been made in https://github.com/apache/couchdb-documentation
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410730971
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   So are you saying that I should leave it this way for SM68, or...?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410587035
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   @davisp As we discussed...this is tricky to get right.
   
   Without this, all JS tests fail with:
   
   ```
   error: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 302 of the JSON data
     
     Loop@/home/jenkins/couchdb/share/server/main.js:8406:16
     @/home/jenkins/couchdb/share/server/main.js:8433:1
     @/home/jenkins/couchdb/share/server/main.js:8434:3
   ```
   
   At least I can confirm `couch_error` is working right, indentation and all! :upside_down_face: 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r409148562
 
 

 ##########
 File path: rebar.config.script
 ##########
 @@ -162,18 +162,18 @@ DepDescs = [
 {mochiweb,         "mochiweb",         {tag, "v2.20.0"}},
 {meck,             "meck",             {tag, "0.8.8"}},
 {recon,            "recon",            {tag, "2.5.0"}}
-],
+].
 
-WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true},
+WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true}.
 
 OptionalDeps = case WithProper of
     true ->
         [{proper, {url, "https://github.com/proper-testing/proper"}, {tag, "v1.3"}}];
     false ->
         []
-end,
+end.
 
 Review comment:
   Ah, that's more or less what i assumed. I'm fine not breaking it out into a separate commit.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410749418
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   Removed the length and it works fine.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408977026
 
 

 ##########
 File path: src/couch/priv/couch_js/68/utf8.cpp
 ##########
 @@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <jsapi.h>
+#include <js/Initialization.h>
+#include <js/Conversions.h>
+#include <js/MemoryFunctions.h>
+#include <js/Wrapper.h>
+#include "config.h"
+#include "util.h"
+
+static int
+enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
+{
+    int utf8Length = 1;
+
+    if (ucs4Char < 0x80)
+    {
+        *utf8Buffer = (uint8_t)ucs4Char;
+    }
+    else
+    {
+        int i;
+        uint32_t a = ucs4Char >> 11;
+        utf8Length = 2;
+        while(a)
+        {
+            a >>= 5;
+            utf8Length++;
+        }
+        i = utf8Length;
+        while(--i)
+        {
+            utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
+            ucs4Char >>= 6;
+        }
+        *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+    }
+
+    return utf8Length;
+}
+
+static bool
+enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
+{
+    size_t i;
+    size_t utf8Len;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+    char16_t c;
+    char16_t c2;
+    uint32_t v;
+    uint8_t utf8buf[6];
+
+    if(!dst)
+    {
+        dstlen = origDstlen = (size_t) -1;
+    }
+
+    while(srclen)
+    {
+        c = *src++;
+        srclen--;
+
+        if(c <= 0xD7FF || c >= 0xE000)
+        {
+            v = (uint32_t) c;
+        }
+        else if(c >= 0xD800 && c <= 0xDBFF)
+        {
+            if(srclen < 1) goto buffer_too_small;
+            c2 = *src++;
+            srclen--;
+            if(c2 >= 0xDC00 && c2 <= 0xDFFF)
+            {
+                v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
+            }
+            else
+            {
+                // Invalid second half of surrogate pair
+                v = (uint32_t) 0xFFFD;
+                // Undo our character advancement
+                src--;
+                srclen++;
+            }
+        }
+        else
+        {
+            // Invalid first half surrogate pair
+            v = (uint32_t) 0xFFFD;
+        }
+
+        if(v < 0x0080)
+        {
+            // no encoding necessary - performance hack
+            if(!dstlen) goto buffer_too_small;
+            if(dst) *dst++ = (char) v;
+            utf8Len = 1;
+        }
+        else
+        {
+            utf8Len = enc_char(utf8buf, v);
+            if(utf8Len > dstlen) goto buffer_too_small;
+            if(dst)
+            {
+                for (i = 0; i < utf8Len; i++)
+                {
+                    *dst++ = (char) utf8buf[i];
+                }
+            }
+        }
+        dstlen -= utf8Len;
+    }
+    
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+char*
+enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
+{
+    JSString* str = NULL;
+    const char16_t* src = NULL;
+    char* bytes = NULL;
+    size_t srclen = 0;
+    size_t byteslen = 0;
+    JS::AutoStableStringChars rawChars(cx);
+    
+    str = arg.toString();
+    if(!str) goto error;
+
+    if (!rawChars.initTwoByte(cx, str))
+        return NULL;
+
+    src = rawChars.twoByteRange().begin().get();
+    srclen = JS_GetStringLength(str);
+
+    if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
+    
+    //bytes = static_cast<char *>(JS_malloc(cx, (byteslen) + 1));
+    bytes = js_pod_malloc<char>(byteslen + 1);
+    bytes[byteslen] = 0;
+    
+    if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
+
+    if(buflen) *buflen = byteslen;
+    goto success;
+
+error:
+    if(bytes != NULL) JS_free(cx, bytes);
+    bytes = NULL;
+
+success:
+/*
+    JS::RootedString str(cx, arg.toString());
+    JS::UniqueChars chars = JS_EncodeStringToUTF8(cx, str);
+
+    if(buflen) *buflen = strlen(chars.get());
+    
+    return JS_NewUCStringCopyN(cs, chars.get(), buflen);
+*/
+    return bytes;
+}
+
+static uint32_t
+dec_char(const uint8_t *utf8Buffer, int utf8Length)
+{
+    uint32_t ucs4Char;
+    uint32_t minucs4Char;
+
+    // from Unicode 3.1, non-shortest form is illegal
+    static const uint32_t minucs4Table[] = {
+        0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+    };
+
+    if (utf8Length == 1)
+    {
+        ucs4Char = *utf8Buffer;
+    }
+    else
+    {
+        ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+        minucs4Char = minucs4Table[utf8Length-2];
+        while(--utf8Length)
+        {
+            ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+        }
+        if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
+        {
+            ucs4Char = 0xFFFD;
+        }
+    }
+
+    return ucs4Char;
+}
+
+static bool
+dec_charbuf(const char *src, size_t srclen, char16_t *dst, size_t *dstlenp)
+{
+    uint32_t v;
+    size_t offset = 0;
+    size_t j;
+    size_t n;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+
+    if(!dst) dstlen = origDstlen = (size_t) -1;
+
+    while(srclen)
+    {
+        v = (uint8_t) *src;
+        n = 1;
+        
+        if(v & 0x80)
+        {
+            while(v & (0x80 >> n))
+            {
+                n++;
+            }
+            
+            if(n > srclen) goto buffer_too_small;
+            if(n == 1 || n > 6) goto bad_character;
+            
+            for(j = 1; j < n; j++)
+            {
+                if((src[j] & 0xC0) != 0x80) goto bad_character;
+            }
+
+            v = dec_char((const uint8_t *) src, n);
+            if(v >= 0x10000)
+            {
+                v -= 0x10000;
+                
+                if(v > 0xFFFFF || dstlen < 2)
+                {
+                    *dstlenp = (origDstlen - dstlen);
+                    return false;
+                }
+                
+                if(dstlen < 2) goto buffer_too_small;
+
+                if(dst)
+                {
+                    *dst++ = (char16_t)((v >> 10) + 0xD800);
+                    v = (char16_t)((v & 0x3FF) + 0xDC00);
+                }
+                dstlen--;
+            }
+        }
+
+        if(!dstlen) goto buffer_too_small;
+        if(dst) *dst++ = (char16_t) v;
+
+        dstlen--;
+        offset += n;
+        src += n;
+        srclen -= n;
+    }
+
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+bad_character:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+JSString*
+dec_string(JSContext* cx, const char* bytes, size_t byteslen)
+{
+    JSString* str = NULL;
+    size_t charslen;
+    
+    if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) return NULL;
+
+    JS::UniqueTwoByteChars chars(js_pod_malloc<char16_t>(charslen + 1));
+    if(!chars) return NULL;
+    chars.get()[charslen] = 0;
+
+    if(!dec_charbuf(bytes, byteslen, chars.get(), &charslen)) goto error;
+
+    str = JS_NewUCString(cx, std::move(chars), charslen - 1);
 
 Review comment:
   Trial & error plus multiple places where this is done over in `js/src/shell/js.cpp`.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r409187423
 
 

 ##########
 File path: src/couch/priv/couch_js/68/utf8.cpp
 ##########
 @@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <jsapi.h>
+#include <js/Initialization.h>
+#include <js/Conversions.h>
+#include <js/MemoryFunctions.h>
+#include <js/Wrapper.h>
+#include "config.h"
+#include "util.h"
+
+static int
+enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
+{
+    int utf8Length = 1;
+
+    if (ucs4Char < 0x80)
+    {
+        *utf8Buffer = (uint8_t)ucs4Char;
+    }
+    else
+    {
+        int i;
+        uint32_t a = ucs4Char >> 11;
+        utf8Length = 2;
+        while(a)
+        {
+            a >>= 5;
+            utf8Length++;
+        }
+        i = utf8Length;
+        while(--i)
+        {
+            utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
+            ucs4Char >>= 6;
+        }
+        *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+    }
+
+    return utf8Length;
+}
+
+static bool
+enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
+{
+    size_t i;
+    size_t utf8Len;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+    char16_t c;
+    char16_t c2;
+    uint32_t v;
+    uint8_t utf8buf[6];
+
+    if(!dst)
+    {
+        dstlen = origDstlen = (size_t) -1;
+    }
+
+    while(srclen)
+    {
+        c = *src++;
+        srclen--;
+
+        if(c <= 0xD7FF || c >= 0xE000)
+        {
+            v = (uint32_t) c;
+        }
+        else if(c >= 0xD800 && c <= 0xDBFF)
+        {
+            if(srclen < 1) goto buffer_too_small;
+            c2 = *src++;
+            srclen--;
+            if(c2 >= 0xDC00 && c2 <= 0xDFFF)
+            {
+                v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
+            }
+            else
+            {
+                // Invalid second half of surrogate pair
+                v = (uint32_t) 0xFFFD;
+                // Undo our character advancement
+                src--;
+                srclen++;
+            }
+        }
+        else
+        {
+            // Invalid first half surrogate pair
+            v = (uint32_t) 0xFFFD;
+        }
+
+        if(v < 0x0080)
+        {
+            // no encoding necessary - performance hack
+            if(!dstlen) goto buffer_too_small;
+            if(dst) *dst++ = (char) v;
+            utf8Len = 1;
+        }
+        else
+        {
+            utf8Len = enc_char(utf8buf, v);
+            if(utf8Len > dstlen) goto buffer_too_small;
+            if(dst)
+            {
+                for (i = 0; i < utf8Len; i++)
+                {
+                    *dst++ = (char) utf8buf[i];
+                }
+            }
+        }
+        dstlen -= utf8Len;
+    }
+    
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+char*
+enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
+{
+    JSString* str = NULL;
+    const char16_t* src = NULL;
+    char* bytes = NULL;
+    size_t srclen = 0;
+    size_t byteslen = 0;
+    JS::AutoStableStringChars rawChars(cx);
+    
+    str = arg.toString();
+    if(!str) goto error;
+
+    if (!rawChars.initTwoByte(cx, str))
+        return NULL;
+
+    src = rawChars.twoByteRange().begin().get();
+    srclen = JS_GetStringLength(str);
+
+    if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
+    
+    //bytes = static_cast<char *>(JS_malloc(cx, (byteslen) + 1));
+    bytes = js_pod_malloc<char>(byteslen + 1);
+    bytes[byteslen] = 0;
+    
+    if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
+
+    if(buflen) *buflen = byteslen;
+    goto success;
+
+error:
+    if(bytes != NULL) JS_free(cx, bytes);
+    bytes = NULL;
+
+success:
+/*
+    JS::RootedString str(cx, arg.toString());
+    JS::UniqueChars chars = JS_EncodeStringToUTF8(cx, str);
+
+    if(buflen) *buflen = strlen(chars.get());
+    
+    return JS_NewUCStringCopyN(cs, chars.get(), buflen);
+*/
+    return bytes;
+}
+
+static uint32_t
+dec_char(const uint8_t *utf8Buffer, int utf8Length)
+{
+    uint32_t ucs4Char;
+    uint32_t minucs4Char;
+
+    // from Unicode 3.1, non-shortest form is illegal
+    static const uint32_t minucs4Table[] = {
+        0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+    };
+
+    if (utf8Length == 1)
+    {
+        ucs4Char = *utf8Buffer;
+    }
+    else
+    {
+        ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+        minucs4Char = minucs4Table[utf8Length-2];
+        while(--utf8Length)
+        {
+            ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+        }
+        if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
+        {
+            ucs4Char = 0xFFFD;
+        }
+    }
+
+    return ucs4Char;
+}
+
+static bool
+dec_charbuf(const char *src, size_t srclen, char16_t *dst, size_t *dstlenp)
+{
+    uint32_t v;
+    size_t offset = 0;
+    size_t j;
+    size_t n;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+
+    if(!dst) dstlen = origDstlen = (size_t) -1;
+
+    while(srclen)
+    {
+        v = (uint8_t) *src;
+        n = 1;
+        
+        if(v & 0x80)
+        {
+            while(v & (0x80 >> n))
+            {
+                n++;
+            }
+            
+            if(n > srclen) goto buffer_too_small;
+            if(n == 1 || n > 6) goto bad_character;
+            
+            for(j = 1; j < n; j++)
+            {
+                if((src[j] & 0xC0) != 0x80) goto bad_character;
+            }
+
+            v = dec_char((const uint8_t *) src, n);
+            if(v >= 0x10000)
+            {
+                v -= 0x10000;
+                
+                if(v > 0xFFFFF || dstlen < 2)
+                {
+                    *dstlenp = (origDstlen - dstlen);
+                    return false;
+                }
+                
+                if(dstlen < 2) goto buffer_too_small;
+
+                if(dst)
+                {
+                    *dst++ = (char16_t)((v >> 10) + 0xD800);
+                    v = (char16_t)((v & 0x3FF) + 0xDC00);
+                }
+                dstlen--;
+            }
+        }
+
+        if(!dstlen) goto buffer_too_small;
+        if(dst) *dst++ = (char16_t) v;
+
+        dstlen--;
+        offset += n;
+        src += n;
+        srclen -= n;
+    }
+
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+bad_character:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+JSString*
+dec_string(JSContext* cx, const char* bytes, size_t byteslen)
+{
+    JSString* str = NULL;
+    size_t charslen;
+    
+    if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) return NULL;
+
+    JS::UniqueTwoByteChars chars(js_pod_malloc<char16_t>(charslen + 1));
+    if(!chars) return NULL;
+    chars.get()[charslen] = 0;
+
+    if(!dec_charbuf(bytes, byteslen, chars.get(), &charslen)) goto error;
+
+    str = JS_NewUCString(cx, std::move(chars), charslen - 1);
 
 Review comment:
   @davisp FYI, if you leave off the `std::move()` here, compile fails with this informative error - probably intentional on Mozilla's part:
   
   ```
   Compiling /home/jenkins/couchdb/src/couch/priv/couch_js/68/utf8.cpp
   /home/jenkins/couchdb/src/couch/priv/couch_js/68/utf8.cpp: In function 'JSString* dec_string(JSContext*, const char*, size_t)':
   /home/jenkins/couchdb/src/couch/priv/couch_js/68/utf8.cpp:299:49: error: use of deleted function 'mozilla::UniquePtr<T [], D>::UniquePtr(const mozilla::UniquePtr<T [], D>&) [with T = char16_t; D = JS::FreePolicy]'
     299 |     str = JS_NewUCString(cx, chars, charslen - 1);
         |                                                 ^
   In file included from /usr/include/mozjs-68/mozilla/Span.h:31,
                    from /usr/include/mozjs-68/mozilla/Range.h:12,
                    from /usr/include/mozjs-68/jsapi.h:15,
                    from /home/jenkins/couchdb/src/couch/priv/couch_js/68/utf8.cpp:13:
   /usr/include/mozjs-68/mozilla/UniquePtr.h:455:3: note: declared here
     455 |   UniquePtr(const UniquePtr& aOther) = delete;  // construct using std::move()!
         |   ^~~~~~~~~
   In file included from /home/jenkins/couchdb/src/couch/priv/couch_js/68/utf8.cpp:13:
   /usr/include/mozjs-68/jsapi.h:2355:70: note:   initializing argument 2 of 'JSString* JS_NewUCString(JSContext*, JS::UniqueTwoByteChars, size_t)'
    2355 |                                               JS::UniqueTwoByteChars chars,
         |                                               ~~~~~~~~~~~~~~~~~~~~~~~^~~~~
   ERROR: compile failed while processing /home/jenkins/couchdb/src/couch: rebar_abort
   ```
   
   Looks to me like they both intentionally deleted the function it could have used, _and_ put that helpful comment there to help you out.
   
   That convinced me, finally, that `std::move()` here is necessary and sufficient.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-615908500
 
 
   Ah derps. I'll add a commit here to remove that debug logging. I'll dig into that test failure and the Compartment/Realm duality as well. I'm on ops so might have some idle time to think hard.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-615947857
 
 
   Length from the ctor removed, and L140 debugging output also removed.
   
   Still need to fix the failing test case and confirm the Realm/Compartment partitioning.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410726205
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   This goes to stderr so it'd be in `/etc/sv/couchdb/logs/main/current` as opposed to what gets shipped out over rsyslog (assuming runit and that runit isn't configured for rsyslog).

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410603580
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   I'll note though that this is counter to something @kocolosk was working on to ensure flattening of all errors in `couch.log` to a single line, though I imagine we can "fix that in post" as they say.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali edited a comment on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali edited a comment on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-615547718
 
 
   @davisp So this now passes `make elixir` and `make javascript`, but fails on `make eunit` with the following log output:
   
   ```
   module 'couch_js_tests'
     Test couchjs
       couch_js_tests: couch_js_test_...[0.066 s] ok
       couch_js_tests: couch_js_test_...[0.063 s] ok
       couch_js_tests: couch_js_test_...[0.063 s] ok
       couch_js_tests: couch_js_test_...*failed*
   in function couch_util:json_decode/2 (src/couch_util.erl, line 508)
   in call from couch_js_tests:should_replace_broken_utf16/0 (test/eunit/couch_js_tests.erl, line 102)
   **throw:{invalid_json,{11,invalid_string}}
     output:<<"">>
   
       couch_js_tests: couch_js_test_...<<208,188,208,176,208,188,208,176,32,208,188,209,139,208,187,208,176,32,209,128,208,176,208,188,209,131>>
   [[[<<108,101,110,103,116,104>>,14]],[[<<115,117,98,115,116,114,105,110,103>>,<<208,188,209,139,208,187,208,176>>]],[[<<115,108,105,99,101>>,<<208,188,208,176,208,188,208,176>>]]]
   [0.069 s] ok
       couch_js_tests: couch_js_test_...out of memory
   [1.258 s] ok
   ```
   
   Can you help?
   
   Also, should we remove the `io:format` from L140 of that test file?
   ```
       io:format(standard_error, "~w~n~w~n", [MomWashedTheFrame, Result]),
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410726364
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   Also that "invalid whitespace after JSON data" is that `std::string` constructor issue I was telling you about. Its because we've included the null byte in the length we gave the constructor instead of the pointer-only constructor that stops at the first null byte.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408949715
 
 

 ##########
 File path: src/couch/priv/couch_js/68/utf8.cpp
 ##########
 @@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <jsapi.h>
+#include <js/Initialization.h>
+#include <js/Conversions.h>
+#include <js/MemoryFunctions.h>
+#include <js/Wrapper.h>
+#include "config.h"
+#include "util.h"
+
+static int
+enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
+{
+    int utf8Length = 1;
+
+    if (ucs4Char < 0x80)
+    {
+        *utf8Buffer = (uint8_t)ucs4Char;
+    }
+    else
+    {
+        int i;
+        uint32_t a = ucs4Char >> 11;
+        utf8Length = 2;
+        while(a)
+        {
+            a >>= 5;
+            utf8Length++;
+        }
+        i = utf8Length;
+        while(--i)
+        {
+            utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
+            ucs4Char >>= 6;
+        }
+        *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+    }
+
+    return utf8Length;
+}
+
+static bool
+enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
+{
+    size_t i;
+    size_t utf8Len;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+    char16_t c;
+    char16_t c2;
+    uint32_t v;
+    uint8_t utf8buf[6];
+
+    if(!dst)
+    {
+        dstlen = origDstlen = (size_t) -1;
+    }
+
+    while(srclen)
+    {
+        c = *src++;
+        srclen--;
+
+        if(c <= 0xD7FF || c >= 0xE000)
+        {
+            v = (uint32_t) c;
+        }
+        else if(c >= 0xD800 && c <= 0xDBFF)
+        {
+            if(srclen < 1) goto buffer_too_small;
+            c2 = *src++;
+            srclen--;
+            if(c2 >= 0xDC00 && c2 <= 0xDFFF)
+            {
+                v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
+            }
+            else
+            {
+                // Invalid second half of surrogate pair
+                v = (uint32_t) 0xFFFD;
+                // Undo our character advancement
+                src--;
+                srclen++;
+            }
+        }
+        else
+        {
+            // Invalid first half surrogate pair
+            v = (uint32_t) 0xFFFD;
+        }
+
+        if(v < 0x0080)
+        {
+            // no encoding necessary - performance hack
+            if(!dstlen) goto buffer_too_small;
+            if(dst) *dst++ = (char) v;
+            utf8Len = 1;
+        }
+        else
+        {
+            utf8Len = enc_char(utf8buf, v);
+            if(utf8Len > dstlen) goto buffer_too_small;
+            if(dst)
+            {
+                for (i = 0; i < utf8Len; i++)
+                {
+                    *dst++ = (char) utf8buf[i];
+                }
+            }
+        }
+        dstlen -= utf8Len;
+    }
+    
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+char*
+enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
+{
+    JSString* str = NULL;
+    const char16_t* src = NULL;
+    char* bytes = NULL;
+    size_t srclen = 0;
+    size_t byteslen = 0;
+    JS::AutoStableStringChars rawChars(cx);
+    
+    str = arg.toString();
+    if(!str) goto error;
+
+    if (!rawChars.initTwoByte(cx, str))
+        return NULL;
+
+    src = rawChars.twoByteRange().begin().get();
+    srclen = JS_GetStringLength(str);
+
+    if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
+    
+    //bytes = static_cast<char *>(JS_malloc(cx, (byteslen) + 1));
+    bytes = js_pod_malloc<char>(byteslen + 1);
+    bytes[byteslen] = 0;
+    
+    if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
+
+    if(buflen) *buflen = byteslen;
+    goto success;
+
+error:
+    if(bytes != NULL) JS_free(cx, bytes);
+    bytes = NULL;
+
+success:
+/*
+    JS::RootedString str(cx, arg.toString());
+    JS::UniqueChars chars = JS_EncodeStringToUTF8(cx, str);
+
+    if(buflen) *buflen = strlen(chars.get());
+    
+    return JS_NewUCStringCopyN(cs, chars.get(), buflen);
+*/
+    return bytes;
+}
+
+static uint32_t
+dec_char(const uint8_t *utf8Buffer, int utf8Length)
+{
+    uint32_t ucs4Char;
+    uint32_t minucs4Char;
+
+    // from Unicode 3.1, non-shortest form is illegal
+    static const uint32_t minucs4Table[] = {
+        0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+    };
+
+    if (utf8Length == 1)
+    {
+        ucs4Char = *utf8Buffer;
+    }
+    else
+    {
+        ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+        minucs4Char = minucs4Table[utf8Length-2];
+        while(--utf8Length)
+        {
+            ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+        }
+        if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
+        {
+            ucs4Char = 0xFFFD;
+        }
+    }
+
+    return ucs4Char;
+}
+
+static bool
+dec_charbuf(const char *src, size_t srclen, char16_t *dst, size_t *dstlenp)
+{
+    uint32_t v;
+    size_t offset = 0;
+    size_t j;
+    size_t n;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+
+    if(!dst) dstlen = origDstlen = (size_t) -1;
+
+    while(srclen)
+    {
+        v = (uint8_t) *src;
+        n = 1;
+        
+        if(v & 0x80)
+        {
+            while(v & (0x80 >> n))
+            {
+                n++;
+            }
+            
+            if(n > srclen) goto buffer_too_small;
+            if(n == 1 || n > 6) goto bad_character;
+            
+            for(j = 1; j < n; j++)
+            {
+                if((src[j] & 0xC0) != 0x80) goto bad_character;
+            }
+
+            v = dec_char((const uint8_t *) src, n);
+            if(v >= 0x10000)
+            {
+                v -= 0x10000;
+                
+                if(v > 0xFFFFF || dstlen < 2)
+                {
+                    *dstlenp = (origDstlen - dstlen);
+                    return false;
+                }
+                
+                if(dstlen < 2) goto buffer_too_small;
+
+                if(dst)
+                {
+                    *dst++ = (char16_t)((v >> 10) + 0xD800);
+                    v = (char16_t)((v & 0x3FF) + 0xDC00);
+                }
+                dstlen--;
+            }
+        }
+
+        if(!dstlen) goto buffer_too_small;
+        if(dst) *dst++ = (char16_t) v;
+
+        dstlen--;
+        offset += n;
+        src += n;
+        srclen -= n;
+    }
+
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+bad_character:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+JSString*
+dec_string(JSContext* cx, const char* bytes, size_t byteslen)
+{
+    JSString* str = NULL;
+    size_t charslen;
+    
+    if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) return NULL;
+
+    JS::UniqueTwoByteChars chars(js_pod_malloc<char16_t>(charslen + 1));
+    if(!chars) return NULL;
+    chars.get()[charslen] = 0;
+
+    if(!dec_charbuf(bytes, byteslen, chars.get(), &charslen)) goto error;
+
+    str = JS_NewUCString(cx, std::move(chars), charslen - 1);
 
 Review comment:
   Where did you see the bit about js_pod_malloc vs JS_alloc? Or was that just trial and error?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-615547799
 
 
   Finally, we need to review https://groups.google.com/forum/#!topic/mozilla.dev.tech.js-engine.internals/4crv5DNVuQk to ensure that our use of Realms vs. Containers holds up in this SM68 world.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-613751273
 
 
   Some sources that really helped me pull this together, for the archives:
   
   * The include headers (of course)
   * https://searchfox.org/ (search all of Mozilla code at once, finds both implementation details for SM as well as some use thereof)
   * https://github.com/GNOME/gjs (GNOME's SM bindings, the reason why libmozjs is still packaged separately for Linux by the packagers)
   * https://groups.google.com/forum/#!topic/mozilla.dev.tech.js-engine.internals/4crv5DNVuQk Discussion of the Container/Realm changes in SM post 60
   * http://thbecker.net/articles/rvalue_references/section_01.html on `std::move()` and rvalues in C++

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408618250
 
 

 ##########
 File path: src/couch/priv/couch_js/68/utf8.cpp
 ##########
 @@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <jsapi.h>
+#include <js/Initialization.h>
+#include <js/Conversions.h>
+#include <js/MemoryFunctions.h>
+#include <js/Wrapper.h>
+#include "config.h"
+#include "util.h"
+
+static int
+enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
+{
+    int utf8Length = 1;
+
+    if (ucs4Char < 0x80)
+    {
+        *utf8Buffer = (uint8_t)ucs4Char;
+    }
+    else
+    {
+        int i;
+        uint32_t a = ucs4Char >> 11;
+        utf8Length = 2;
+        while(a)
+        {
+            a >>= 5;
+            utf8Length++;
+        }
+        i = utf8Length;
+        while(--i)
+        {
+            utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
+            ucs4Char >>= 6;
+        }
+        *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+    }
+
+    return utf8Length;
+}
+
+static bool
+enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
+{
+    size_t i;
+    size_t utf8Len;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+    char16_t c;
+    char16_t c2;
+    uint32_t v;
+    uint8_t utf8buf[6];
+
+    if(!dst)
+    {
+        dstlen = origDstlen = (size_t) -1;
+    }
+
+    while(srclen)
+    {
+        c = *src++;
+        srclen--;
+
+        if(c <= 0xD7FF || c >= 0xE000)
+        {
+            v = (uint32_t) c;
+        }
+        else if(c >= 0xD800 && c <= 0xDBFF)
+        {
+            if(srclen < 1) goto buffer_too_small;
+            c2 = *src++;
+            srclen--;
+            if(c2 >= 0xDC00 && c2 <= 0xDFFF)
+            {
+                v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
+            }
+            else
+            {
+                // Invalid second half of surrogate pair
+                v = (uint32_t) 0xFFFD;
+                // Undo our character advancement
+                src--;
+                srclen++;
+            }
+        }
+        else
+        {
+            // Invalid first half surrogate pair
+            v = (uint32_t) 0xFFFD;
+        }
+
+        if(v < 0x0080)
+        {
+            // no encoding necessary - performance hack
+            if(!dstlen) goto buffer_too_small;
+            if(dst) *dst++ = (char) v;
+            utf8Len = 1;
+        }
+        else
+        {
+            utf8Len = enc_char(utf8buf, v);
+            if(utf8Len > dstlen) goto buffer_too_small;
+            if(dst)
+            {
+                for (i = 0; i < utf8Len; i++)
+                {
+                    *dst++ = (char) utf8buf[i];
+                }
+            }
+        }
+        dstlen -= utf8Len;
+    }
+    
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+char*
+enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
+{
+    JSString* str = NULL;
+    const char16_t* src = NULL;
+    char* bytes = NULL;
+    size_t srclen = 0;
+    size_t byteslen = 0;
+    JS::AutoStableStringChars rawChars(cx);
+    
+    str = arg.toString();
+    if(!str) goto error;
+
+    if (!rawChars.initTwoByte(cx, str))
+        return NULL;
+
+    src = rawChars.twoByteRange().begin().get();
+    srclen = JS_GetStringLength(str);
+
+    if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
+    
+    //bytes = static_cast<char *>(JS_malloc(cx, (byteslen) + 1));
+    bytes = js_pod_malloc<char>(byteslen + 1);
 
 Review comment:
   Just like `dec_string` this has to be `js_pod_malloc`, not `JS_alloc` to prevent problems outside the JS runtime.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408948815
 
 

 ##########
 File path: rebar.config.script
 ##########
 @@ -162,18 +162,18 @@ DepDescs = [
 {mochiweb,         "mochiweb",         {tag, "v2.20.0"}},
 {meck,             "meck",             {tag, "0.8.8"}},
 {recon,            "recon",            {tag, "2.5.0"}}
-],
+].
 
-WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true},
+WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true}.
 
 OptionalDeps = case WithProper of
     true ->
         [{proper, {url, "https://github.com/proper-testing/proper"}, {tag, "v1.3"}}];
     false ->
         []
-end,
+end.
 
 Review comment:
   Why did you change all of the statement separators?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on issue #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on issue #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#issuecomment-615547718
 
 
   @davisp So this now passes `make elixir` and `make javascript`, but fails on `make eunit` with the following log output:
   
   ```
   module 'couch_js_tests'
     Test couchjs
       couch_js_tests: couch_js_test_...[0.066 s] ok
       couch_js_tests: couch_js_test_...[0.063 s] ok
       couch_js_tests: couch_js_test_...[0.063 s] ok
       couch_js_tests: couch_js_test_...*failed*
   in function couch_util:json_decode/2 (src/couch_util.erl, line 508)
   in call from couch_js_tests:should_replace_broken_utf16/0 (test/eunit/couch_js_tests.erl, line 102)
   **throw:{invalid_json,{11,invalid_string}}
     output:<<"">>
   
       couch_js_tests: couch_js_test_...<<208,188,208,176,208,188,208,176,32,208,188,209,139,208,187,208,176,32,209,128,208,176,208,188,209,131>>
   [[[<<108,101,110,103,116,104>>,14]],[[<<115,117,98,115,116,114,105,110,103>>,<<208,188,209,139,208,187,208,176>>]],[[<<115,108,105,99,101>>,<<208,188,208,176,208,188,208,176>>]]]
   [0.069 s] ok
       couch_js_tests: couch_js_test_...out of memory
   [1.258 s] ok
   ```
   
   Can you help?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408977504
 
 

 ##########
 File path: rebar.config.script
 ##########
 @@ -162,18 +162,18 @@ DepDescs = [
 {mochiweb,         "mochiweb",         {tag, "v2.20.0"}},
 {meck,             "meck",             {tag, "0.8.8"}},
 {recon,            "recon",            {tag, "2.5.0"}}
-],
+].
 
-WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true},
+WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true}.
 
 OptionalDeps = case WithProper of
     true ->
         [{proper, {url, "https://github.com/proper-testing/proper"}, {tag, "v1.3"}}];
     false ->
         []
-end,
+end.
 
 Review comment:
   Because I burnt a day on trying to understand why I had a bug that jumped around when I changed `,` to `.`. Bob agreed we should pick one and stick to it. It's unrelated, I can move to a separate commit, but I don't see why we shouldn't do it.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] davisp commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
davisp commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r410746328
 
 

 ##########
 File path: src/couch/priv/couch_js/68/util.cpp
 ##########
 @@ -0,0 +1,368 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+#include <mozilla/Unused.h>
+
+#include "help.h"
+#include "util.h"
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    JSString* ret = JS_NewUCString(cx, std::move(utf16), len);
+
+    if(ret) {
+        // JS_NewUCString took ownership on success. We shift
+        // the resulting pointer into Unused to silence the
+        // compiler warning.
+        mozilla::Unused << utf16.release();
+    }
+
+    return ret;
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->use_http = 0;
+    args->use_test_funs = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+    args->uri_file = nullptr;
+    args->uri = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-H", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("-T", argv[i]) == 0) {
+            args->use_test_funs = 1;
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("-u", argv[i]) == 0) {
+            args->uri_file = argv[++i];
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp, byteslen - 1));
 
 Review comment:
   I was saying I think we should not specify a length in the constructor, sorry.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [couchdb] wohali commented on a change in pull request #2788: SpiderMonkey 68 support

Posted by GitBox <gi...@apache.org>.
wohali commented on a change in pull request #2788: SpiderMonkey 68 support
URL: https://github.com/apache/couchdb/pull/2788#discussion_r408610575
 
 

 ##########
 File path: src/couch/priv/couch_js/68/utf8.cpp
 ##########
 @@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <jsapi.h>
+#include <js/Initialization.h>
+#include <js/Conversions.h>
+#include <js/MemoryFunctions.h>
+#include <js/Wrapper.h>
+#include "config.h"
+#include "util.h"
+
+static int
+enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
+{
+    int utf8Length = 1;
+
+    if (ucs4Char < 0x80)
+    {
+        *utf8Buffer = (uint8_t)ucs4Char;
+    }
+    else
+    {
+        int i;
+        uint32_t a = ucs4Char >> 11;
+        utf8Length = 2;
+        while(a)
+        {
+            a >>= 5;
+            utf8Length++;
+        }
+        i = utf8Length;
+        while(--i)
+        {
+            utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
+            ucs4Char >>= 6;
+        }
+        *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+    }
+
+    return utf8Length;
+}
+
+static bool
+enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
+{
+    size_t i;
+    size_t utf8Len;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+    char16_t c;
+    char16_t c2;
+    uint32_t v;
+    uint8_t utf8buf[6];
+
+    if(!dst)
+    {
+        dstlen = origDstlen = (size_t) -1;
+    }
+
+    while(srclen)
+    {
+        c = *src++;
+        srclen--;
+
+        if(c <= 0xD7FF || c >= 0xE000)
+        {
+            v = (uint32_t) c;
+        }
+        else if(c >= 0xD800 && c <= 0xDBFF)
+        {
+            if(srclen < 1) goto buffer_too_small;
+            c2 = *src++;
+            srclen--;
+            if(c2 >= 0xDC00 && c2 <= 0xDFFF)
+            {
+                v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
+            }
+            else
+            {
+                // Invalid second half of surrogate pair
+                v = (uint32_t) 0xFFFD;
+                // Undo our character advancement
+                src--;
+                srclen++;
+            }
+        }
+        else
+        {
+            // Invalid first half surrogate pair
+            v = (uint32_t) 0xFFFD;
+        }
+
+        if(v < 0x0080)
+        {
+            // no encoding necessary - performance hack
+            if(!dstlen) goto buffer_too_small;
+            if(dst) *dst++ = (char) v;
+            utf8Len = 1;
+        }
+        else
+        {
+            utf8Len = enc_char(utf8buf, v);
+            if(utf8Len > dstlen) goto buffer_too_small;
+            if(dst)
+            {
+                for (i = 0; i < utf8Len; i++)
+                {
+                    *dst++ = (char) utf8buf[i];
+                }
+            }
+        }
+        dstlen -= utf8Len;
+    }
+    
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+char*
+enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
+{
+    JSString* str = NULL;
+    const char16_t* src = NULL;
+    char* bytes = NULL;
+    size_t srclen = 0;
+    size_t byteslen = 0;
+    JS::AutoStableStringChars rawChars(cx);
+    
+    str = arg.toString();
+    if(!str) goto error;
+
+    if (!rawChars.initTwoByte(cx, str))
+        return NULL;
+
+    src = rawChars.twoByteRange().begin().get();
+    srclen = JS_GetStringLength(str);
+
+    if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
+    
+    //bytes = static_cast<char *>(JS_malloc(cx, (byteslen) + 1));
+    bytes = js_pod_malloc<char>(byteslen + 1);
+    bytes[byteslen] = 0;
+    
+    if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
+
+    if(buflen) *buflen = byteslen;
+    goto success;
+
+error:
+    if(bytes != NULL) JS_free(cx, bytes);
+    bytes = NULL;
+
+success:
+/*
+    JS::RootedString str(cx, arg.toString());
+    JS::UniqueChars chars = JS_EncodeStringToUTF8(cx, str);
+
+    if(buflen) *buflen = strlen(chars.get());
+    
+    return JS_NewUCStringCopyN(cs, chars.get(), buflen);
+*/
+    return bytes;
+}
+
+static uint32_t
+dec_char(const uint8_t *utf8Buffer, int utf8Length)
+{
+    uint32_t ucs4Char;
+    uint32_t minucs4Char;
+
+    // from Unicode 3.1, non-shortest form is illegal
+    static const uint32_t minucs4Table[] = {
+        0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+    };
+
+    if (utf8Length == 1)
+    {
+        ucs4Char = *utf8Buffer;
+    }
+    else
+    {
+        ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+        minucs4Char = minucs4Table[utf8Length-2];
+        while(--utf8Length)
+        {
+            ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+        }
+        if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
+        {
+            ucs4Char = 0xFFFD;
+        }
+    }
+
+    return ucs4Char;
+}
+
+static bool
+dec_charbuf(const char *src, size_t srclen, char16_t *dst, size_t *dstlenp)
+{
+    uint32_t v;
+    size_t offset = 0;
+    size_t j;
+    size_t n;
+    size_t dstlen = *dstlenp;
+    size_t origDstlen = dstlen;
+
+    if(!dst) dstlen = origDstlen = (size_t) -1;
+
+    while(srclen)
+    {
+        v = (uint8_t) *src;
+        n = 1;
+        
+        if(v & 0x80)
+        {
+            while(v & (0x80 >> n))
+            {
+                n++;
+            }
+            
+            if(n > srclen) goto buffer_too_small;
+            if(n == 1 || n > 6) goto bad_character;
+            
+            for(j = 1; j < n; j++)
+            {
+                if((src[j] & 0xC0) != 0x80) goto bad_character;
+            }
+
+            v = dec_char((const uint8_t *) src, n);
+            if(v >= 0x10000)
+            {
+                v -= 0x10000;
+                
+                if(v > 0xFFFFF || dstlen < 2)
+                {
+                    *dstlenp = (origDstlen - dstlen);
+                    return false;
+                }
+                
+                if(dstlen < 2) goto buffer_too_small;
+
+                if(dst)
+                {
+                    *dst++ = (char16_t)((v >> 10) + 0xD800);
+                    v = (char16_t)((v & 0x3FF) + 0xDC00);
+                }
+                dstlen--;
+            }
+        }
+
+        if(!dstlen) goto buffer_too_small;
+        if(dst) *dst++ = (char16_t) v;
+
+        dstlen--;
+        offset += n;
+        src += n;
+        srclen -= n;
+    }
+
+    *dstlenp = (origDstlen - dstlen);
+    return true;
+
+bad_character:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+
+buffer_too_small:
+    *dstlenp = (origDstlen - dstlen);
+    return false;
+}
+
+JSString*
+dec_string(JSContext* cx, const char* bytes, size_t byteslen)
+{
+    JSString* str = NULL;
+    size_t charslen;
+    
+    if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) return NULL;
+
+    JS::UniqueTwoByteChars chars(js_pod_malloc<char16_t>(charslen + 1));
+    if(!chars) return NULL;
+    chars.get()[charslen] = 0;
+
+    if(!dec_charbuf(bytes, byteslen, chars.get(), &charslen)) goto error;
+
+    str = JS_NewUCString(cx, std::move(chars), charslen - 1);
 
 Review comment:
   The requirement here is the use of `js_pod_malloc` on L293, to prevent reaping of the memory when going out of the JS realm (this happens with the http bindings), combined with `std::move` here, necessary per the header file which actually deletes the ctor if you refuse to use it.
   
   Drop either of those decisions and you get either double `free()`s or segfaults.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services