. auto/feature
+ njs_feature="QuickJS JS_NewArrayBuffer() with max_len"
+ njs_feature_name=NJS_HAVE_QUICKJS_ARRAY_BUFFER_MAX_LEN
+ njs_feature_run=no
+ njs_feature_test="#include <quickjs_compat.h>
+
+ static void *
+ realloc_func(JSRuntime *rt, void *opaque, void *ptr,
+ size_t size)
+ {
+ return NULL;
+ }
+
+ int main() {
+ JSRuntime *rt;
+ JSContext *ctx;
+
+ rt = JS_NewRuntime();
+ ctx = JS_NewContext(rt);
+ (void) JS_NewArrayBuffer(ctx, NULL, 0, 0,
+ realloc_func, NULL, 0);
+ JS_FreeContext(ctx);
+ JS_FreeRuntime(rt);
+ return 0;
+ }"
+
+ . auto/feature
+
njs_feature="QuickJS JS_NewError() attaches stack"
njs_feature_run=value
njs_feature_name=NJS_HAVE_QUICKJS_NEW_ERROR_STACK
pthread_cond_signal(&console->agent_cond);
pthread_mutex_unlock(&console->agent_mutex);
- args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf,
- agent->broadcast_sab_size,
- NULL, NULL, 1);
+ args[0] = qjs_new_external_array_buffer(ctx,
+ agent->broadcast_sab_buf, agent->broadcast_sab_size, 1);
args[1] = JS_NewInt32(ctx, agent->broadcast_val);
ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED,
switch (type) {
case NGX_JS_BODY_ARRAY_BUFFER:
- return JS_NewArrayBuffer(cx, ctx->body_read_data,
- ctx->body_read_len, NULL, NULL, 0);
+ return qjs_new_external_array_buffer(cx, ctx->body_read_data,
+ ctx->body_read_len, 0);
case NGX_JS_BODY_JSON:
if (ctx->body_read_nul) {
switch (magic) {
case NGX_JS_BODY_ARRAY_BUFFER:
/*
- * no free_func for JS_NewArrayBuffer()
- * because request->body is allocated from e->pool
+ * request->body is allocated from e->pool
* and will be freed when context is freed.
*/
- result = JS_NewArrayBuffer(cx, request->body.data, request->body.len,
- NULL, NULL, 0);
+ result = qjs_new_external_array_buffer(cx, request->body.data,
+ request->body.len, 0);
if (JS_IsException(result)) {
return JS_ThrowOutOfMemory(cx);
}
}
/*
- * no free_func for JS_NewArrayBuffer()
- * because string.start is allocated from e->pool
+ * string.start is allocated from e->pool
* and will be freed when context is freed.
*/
- result = JS_NewArrayBuffer(cx, string.start, string.length, NULL, NULL,
- 0);
+ result = qjs_new_external_array_buffer(cx, string.start,
+ string.length, 0);
if (JS_IsException(result)) {
return JS_ThrowOutOfMemory(cx);
}
}
+#ifdef NJS_HAVE_QUICKJS_ARRAY_BUFFER_MAX_LEN
+
+#define qjs_array_buffer_create(cx, src, len, free, shared) \
+ JS_NewArrayBuffer(cx, src, len, 0, free, NULL, shared)
+
+
+/*
+ * ArrayBuffer.prototype.transfer() reallocates the data even when the
+ * buffer is not resizable, so the whole realloc contract has to be
+ * implemented here.
+ */
+
+static void *
+qjs_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr, size_t size)
+{
+ if (size == 0) {
+ js_free_rt(rt, ptr);
+ return NULL;
+ }
+
+ return js_realloc_rt(rt, ptr, size);
+}
+
+#else
+
+#define qjs_array_buffer_create(cx, src, len, free, shared) \
+ JS_NewArrayBuffer(cx, src, len, free, NULL, shared)
+
+
static void
-js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
+qjs_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
{
js_free_rt(rt, ptr);
}
+#endif
+
JSValue
qjs_new_array_buffer(JSContext *cx, uint8_t *src, size_t len)
{
- return JS_NewArrayBuffer(cx, src, len, js_array_buffer_free, NULL, 0);
+ return qjs_array_buffer_create(cx, src, len, qjs_array_buffer_free, 0);
+}
+
+
+/*
+ * The memory is not managed by the engine, the caller is responsible for
+ * keeping it alive while the buffer is reachable.
+ */
+
+JSValue
+qjs_new_external_array_buffer(JSContext *cx, uint8_t *src, size_t len,
+ int is_shared)
+{
+ return qjs_array_buffer_create(cx, src, len, NULL, is_shared);
}
#include <quickjs_compat.h>
+/*
+ * The engine reserves class ids below JS_CLASS_INIT_COUNT for its own
+ * classes. The value is internal and grows between releases, so the ids
+ * below start far enough above it.
+ */
+#define QJS_CORE_CLASS_ID_OFFSET 128
+
enum {
- QJS_CORE_CLASS_ID_BUFFER = 64,
+ QJS_CORE_CLASS_ID_BUFFER = QJS_CORE_CLASS_ID_OFFSET,
QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR,
QJS_CORE_CLASS_ID_TEXT_DECODER,
QJS_CORE_CLASS_ID_TEXT_ENCODER,
JSValue qjs_new_uint8_array(JSContext *ctx, int argc, JSValueConst *argv);
JSValue qjs_new_array_buffer(JSContext *cx, uint8_t *src, size_t len);
+JSValue qjs_new_external_array_buffer(JSContext *cx, uint8_t *src, size_t len,
+ int is_shared);
JSValue qjs_buffer_alloc(JSContext *ctx, size_t size);
JSValue qjs_buffer_create(JSContext *ctx, u_char *start, size_t size);
JSValue qjs_buffer_chb_alloc(JSContext *ctx, njs_chb_t *chain);
JSValue global_obj, buffer, proto, ctor, ta, ta_proto, symbol, species;
JSClassID u8_ta_class_id;
- JS_NewClass(JS_GetRuntime(ctx), QJS_CORE_CLASS_ID_BUFFER,
- &qjs_buffer_class);
+ if (JS_NewClass(JS_GetRuntime(ctx), QJS_CORE_CLASS_ID_BUFFER,
+ &qjs_buffer_class) < 0)
+ {
+ return -1;
+ }
global_obj = JS_GetGlobalObject(ctx);
* We use JS_SetClassProto()/JS_GetClassProto() as a key-value store
* for fast value query by class ID without querying the global object.
*/
- JS_NewClass(JS_GetRuntime(ctx), QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR,
- &qjs_uint8_array_ctor_class);
+ if (JS_NewClass(JS_GetRuntime(ctx), QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR,
+ &qjs_uint8_array_ctor_class) < 0)
+ {
+ return -1;
+ }
+
JS_SetClassProto(ctx, QJS_CORE_CLASS_ID_UINT8_ARRAY_CTOR,
JS_DupValue(ctx, ctor));
#endif