This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch update_quick_js
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit f86be0e8aee833217aeec1cb70ca29860ee09f9b
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Mon Nov 3 17:48:00 2025 -0500

    Update Quickjs: optimize global var access, fix use-after-free error
    
    Optimized global variable access
    
https://github.com/bellard/quickjs/commit/a6816be23ae2bc511c7797489326f58934968323
    
    Much faster destructuring at the expense of a slight incompatibility
    with the spec when direct evals are present (v8 behaves the same way)
    
https://github.com/bellard/quickjs/commit/e015918dd834946a20b423310f7db812f63ce251
    
    Remove duplicate test
    
https://github.com/bellard/quickjs/commit/961478d7bb1c4be7d0923cbf30032c15d6479af8
    
    qjs `--strict` option (we don't use this)
    
https://github.com/bellard/quickjs/commit/baa186fc6e9c9a196ebceb7b1c762788d2c1517f
    
    Fix use-after-free in Array.prototype.transfer (we don't use this)
    
https://github.com/bellard/quickjs/commit/75b5230000de87a68743bc8791e186137770012f
    
    Fix `DataView` resizing
    
https://github.com/bellard/quickjs/commit/7cfddd06649c08c9dc10c65071ba71910e3de4aa
    
    Fix length check in ArrayBuffer.prototype.slice
    
https://github.com/bellard/quickjs/commit/c6fe5a98fd3ef3b7064e6e0145dfebfe12449fea
    
    More informative "not a constructor" error message
    
https://github.com/bellard/quickjs/commit/080c01f34696351d21f34f99081e93adb41ae74a
---
 .../patches/01-spidermonkey-185-mode.patch         |    6 +-
 src/couch_quickjs/patches/02-test262-errors.patch  |   10 +-
 src/couch_quickjs/quickjs/quickjs-opcode.h         |   11 +-
 src/couch_quickjs/quickjs/quickjs.c                | 1515 ++++++++++++--------
 src/couch_quickjs/quickjs/test262_errors.txt       |   16 +-
 5 files changed, 939 insertions(+), 619 deletions(-)

diff --git a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch 
b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
index 05b8020c7..46f6cd831 100644
--- a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
+++ b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
@@ -1,6 +1,6 @@
---- quickjs-master/quickjs.c   2025-10-18 06:04:12
-+++ quickjs/quickjs.c  2025-10-20 10:47:26
-@@ -31017,10 +31017,24 @@
+--- quickjs-master/quickjs.c   2025-11-03 12:53:32
++++ quickjs/quickjs.c  2025-11-03 16:58:35
+@@ -31279,10 +31279,24 @@
      if (s->token.val == TOK_FUNCTION ||
          (token_is_pseudo_keyword(s, JS_ATOM_async) &&
           peek_token(s, TRUE) == TOK_FUNCTION)) {
diff --git a/src/couch_quickjs/patches/02-test262-errors.patch 
b/src/couch_quickjs/patches/02-test262-errors.patch
index a75d8b978..ac8106bda 100644
--- a/src/couch_quickjs/patches/02-test262-errors.patch
+++ b/src/couch_quickjs/patches/02-test262-errors.patch
@@ -1,8 +1,8 @@
---- quickjs-master/test262_errors.txt  2025-10-18 06:04:12
-+++ quickjs/test262_errors.txt 2025-10-20 10:49:07
-@@ -6,6 +6,8 @@
- 
test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33:
 SyntaxError: invalid assignment left-hand side
- 
test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20:
 SyntaxError: invalid assignment left-hand side
+--- quickjs-master/test262_errors.txt  2025-11-03 12:53:32
++++ quickjs/test262_errors.txt 2025-11-03 16:58:35
+@@ -19,6 +19,8 @@
+ 
test262/test/language/expressions/compound-assignment/S11.13.2_A6.10_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 5
+ 
test262/test/language/expressions/compound-assignment/S11.13.2_A6.11_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 5
  test262/test/language/identifier-resolution/assign-to-global-undefined.js:20: 
strict mode: expected error
 +test262/test/language/statements/expression/S12.4_A1.js:15: unexpected error 
type: Test262: This statement should not be evaluated.
 +test262/test/language/statements/expression/S12.4_A1.js:15: strict mode: 
unexpected error type: Test262: This statement should not be evaluated.
diff --git a/src/couch_quickjs/quickjs/quickjs-opcode.h 
b/src/couch_quickjs/quickjs/quickjs-opcode.h
index 86c3ec406..d93852133 100644
--- a/src/couch_quickjs/quickjs/quickjs-opcode.h
+++ b/src/couch_quickjs/quickjs/quickjs-opcode.h
@@ -123,17 +123,14 @@ DEF(         regexp, 1, 2, 1, none) /* create a RegExp 
object from the pattern a
 DEF(      get_super, 1, 1, 1, none)
 DEF(         import, 1, 2, 1, none) /* dynamic module import */
 
-DEF(  get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not 
exist */
-DEF(        get_var, 5, 0, 1, atom) /* throw an exception if the variable does 
not exist */
-DEF(        put_var, 5, 1, 0, atom) /* must come after get_var */
-DEF(   put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to 
initialize a global lexical variable */
+DEF(  get_var_undef, 3, 0, 1, var_ref) /* push undefined if the variable does 
not exist */
+DEF(        get_var, 3, 0, 1, var_ref) /* throw an exception if the variable 
does not exist */
+DEF(        put_var, 3, 1, 0, var_ref) /* must come after get_var */
+DEF(   put_var_init, 3, 1, 0, var_ref) /* must come after put_var. Used to 
initialize a global lexical variable */
 
 DEF(  get_ref_value, 1, 2, 3, none)
 DEF(  put_ref_value, 1, 3, 0, none)
 
-DEF(     define_var, 6, 0, 0, atom_u8)
-DEF(check_define_var, 6, 0, 0, atom_u8)
-DEF(    define_func, 6, 1, 0, atom_u8)
 DEF(      get_field, 5, 1, 1, atom)
 DEF(     get_field2, 5, 1, 2, atom)
 DEF(      put_field, 5, 2, 0, atom)
diff --git a/src/couch_quickjs/quickjs/quickjs.c 
b/src/couch_quickjs/quickjs/quickjs.c
index 73429a705..c7657971d 100644
--- a/src/couch_quickjs/quickjs/quickjs.c
+++ b/src/couch_quickjs/quickjs/quickjs.c
@@ -166,6 +166,7 @@ enum {
     JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
     JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
     JS_CLASS_GENERATOR,         /* u.generator_data */
+    JS_CLASS_GLOBAL_OBJECT,     /* u.global_object */
     JS_CLASS_PROXY,             /* u.proxy_data */
     JS_CLASS_PROMISE,           /* u.promise_data */
     JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
@@ -378,6 +379,8 @@ typedef struct JSVarRef {
             int __gc_ref_count; /* corresponds to header.ref_count */
             uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
             uint8_t is_detached;
+            uint8_t is_lexical; /* only used with global variables */
+            uint8_t is_const; /* only used with global variables */
         };
     };
     JSValue *pvalue; /* pointer to the value, either on the stack or
@@ -542,11 +545,23 @@ typedef struct JSStringRope {
     JSValue right; /* might be the empty string */
 } JSStringRope;
 
+typedef enum {
+    JS_CLOSURE_LOCAL, /* 'var_idx' is the index of a local variable in the 
parent function */
+    JS_CLOSURE_ARG, /* 'var_idx' is the index of a argument variable in the 
parent function */
+    JS_CLOSURE_REF, /* 'var_idx' is the index of a closure variable in the 
parent function */
+    JS_CLOSURE_GLOBAL_REF, /* 'var_idx' in the index of a closure
+                              variable in the parent function
+                              referencing a global variable */
+    JS_CLOSURE_GLOBAL_DECL, /* global variable declaration (eval code only) */
+    JS_CLOSURE_GLOBAL, /* global variable (eval code only) */
+    JS_CLOSURE_MODULE_DECL, /* definition of a module variable (eval code 
only) */
+    JS_CLOSURE_MODULE_IMPORT, /* definition of a module import (eval code 
only) */ 
+} JSClosureTypeEnum;
+
 typedef struct JSClosureVar {
-    uint8_t is_local : 1;
-    uint8_t is_arg : 1;
-    uint8_t is_const : 1;
-    uint8_t is_lexical : 1;
+    JSClosureTypeEnum closure_type : 3;
+    uint8_t is_lexical : 1; /* lexical variable */
+    uint8_t is_const : 1; /* const variable (is_lexical = 1 if is_const = 1 */
     uint8_t var_kind : 4; /* see JSVarKindEnum */
     /* 8 bits available */
     uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
@@ -576,6 +591,7 @@ typedef enum {
     JS_VAR_PRIVATE_GETTER,
     JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
     JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
+    JS_VAR_GLOBAL_FUNCTION_DECL, /* global function definition, only in 
JSVarDef */
 } JSVarKindEnum;
 
 /* XXX: could use a different structure in bytecode functions to save
@@ -715,6 +731,10 @@ typedef struct JSTypedArray {
     BOOL track_rab; /* auto-track length of backing array buffer */
 } JSTypedArray;
 
+typedef struct JSGlobalObject {
+    JSValue uninitialized_vars; /* hidden object containing the list of 
uninitialized variables */
+} JSGlobalObject;
+
 typedef struct JSAsyncFunctionState {
     JSGCObjectHeader header;
     JSValue this_val; /* 'this' argument */
@@ -1004,6 +1024,7 @@ struct JSObject {
         } array;    /* 12/20 bytes */
         JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
         JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
+        JSGlobalObject global_object;
     } u;
 };
 
@@ -1106,6 +1127,7 @@ static __maybe_unused void JS_DumpString(JSRuntime *rt, 
const JSString *p);
 static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
 static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
 static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
+static __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom 
atom);
 static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, 
JSValueConst val);
 static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, 
JSValueConst val);
 static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
@@ -1156,6 +1178,9 @@ static void js_regexp_string_iterator_mark(JSRuntime *rt, 
JSValueConst val,
 static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
 static void js_generator_mark(JSRuntime *rt, JSValueConst val,
                                 JS_MarkFunc *mark_func);
+static void js_global_object_finalizer(JSRuntime *rt, JSValue obj);
+static void js_global_object_mark(JSRuntime *rt, JSValueConst val,
+                                  JS_MarkFunc *mark_func);
 static void js_promise_finalizer(JSRuntime *rt, JSValue val);
 static void js_promise_mark(JSRuntime *rt, JSValueConst val,
                                 JS_MarkFunc *mark_func);
@@ -1230,6 +1255,7 @@ static BOOL typed_array_is_oob(JSObject *p);
 static int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj);
 static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
 static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx);
+static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical);
 static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
                              BOOL is_arg);
 static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
@@ -1321,6 +1347,8 @@ static JSValue get_date_string(JSContext *ctx, 
JSValueConst this_val,
                                int argc, JSValueConst *argv, int magic);
 static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
                                  int argc, JSValueConst *argv);
+static JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, 
JSObject *p,
+                                                         JSAtom atom, BOOL 
is_lexical);
 
 static const JSClassExoticMethods js_arguments_exotic_methods;
 static const JSClassExoticMethods js_string_exotic_methods;
@@ -1572,6 +1600,7 @@ static JSClassShortDef const js_std_class_def[] = {
     { JS_ATOM_String_Iterator, js_array_iterator_finalizer, 
js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
     { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, 
js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
     { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* 
JS_CLASS_GENERATOR */
+    { JS_ATOM_Object, js_global_object_finalizer, js_global_object_mark }, /* 
JS_CLASS_GLOBAL_OBJECT */
 };
 
 static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
@@ -5239,6 +5268,9 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, 
JSShape *sh, JSClassID clas
         p->u.regexp.pattern = NULL;
         p->u.regexp.bytecode = NULL;
         break;
+    case JS_CLASS_GLOBAL_OBJECT:
+        p->u.global_object.uninitialized_vars = JS_UNDEFINED;
+        break;
     default:
     set_exotic:
         if (ctx->rt->class_array[class_id].exotic) {
@@ -7294,6 +7326,22 @@ static JSValue JS_ThrowTypeErrorNotAnObject(JSContext 
*ctx)
     return JS_ThrowTypeError(ctx, "not an object");
 }
 
+static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx,
+                                                JSValueConst func_obj)
+{
+    const char *name;
+    if (!JS_IsFunction(ctx, func_obj))
+        goto fail;
+    name = get_prop_string(ctx, func_obj, JS_ATOM_name);
+    if (!name) {
+    fail:
+        return JS_ThrowTypeError(ctx, "not a constructor");
+    }
+    JS_ThrowTypeError(ctx, "%s is not a constructor", name);
+    JS_FreeCString(ctx, name);
+    return JS_EXCEPTION;
+}
+
 static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
 {
     return JS_ThrowTypeError(ctx, "not a symbol");
@@ -7680,6 +7728,16 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject 
*p, JSAtom prop,
         prs->flags |= JS_PROP_VARREF;
         pr->u.var_ref = JS_VALUE_GET_PTR(val);
         pr->u.var_ref->header.ref_count++;
+    } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
+        JSVarRef *var_ref;
+        /* in the global object we use references */
+        var_ref = js_create_var_ref(ctx, FALSE);
+        if (!var_ref)
+            return -1;
+        prs->flags |= JS_PROP_VARREF;
+        pr->u.var_ref = var_ref;
+        var_ref->value = val; 
+        var_ref->is_const = !(prs->flags & JS_PROP_WRITABLE);
     } else {
         pr->u.value = val;
     }
@@ -8742,6 +8800,29 @@ static no_inline __exception int 
convert_fast_array_to_array(JSContext *ctx,
     return 0;
 }
 
+static int remove_global_object_property(JSContext *ctx, JSObject *p,
+                                         JSShapeProperty *prs, JSProperty *pr)
+{
+    JSVarRef *var_ref;
+    JSObject *p1;
+    JSProperty *pr1;
+    
+    var_ref = pr->u.var_ref;
+    if (var_ref->header.ref_count == 1)
+        return 0;
+    p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
+    pr1 = add_property(ctx, p1, prs->atom, JS_PROP_C_W_E | JS_PROP_VARREF);
+    if (!pr1)
+        return -1;
+    pr1->u.var_ref = var_ref;
+    var_ref->header.ref_count++;
+    JS_FreeValue(ctx, var_ref->value);
+    var_ref->is_lexical = FALSE;
+    var_ref->is_const = FALSE;
+    var_ref->value = JS_UNINITIALIZED;
+    return 0;
+}
+
 static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
 {
     JSShape *sh;
@@ -8779,6 +8860,11 @@ static int delete_property(JSContext *ctx, JSObject *p, 
JSAtom atom)
             sh->deleted_prop_count++;
             /* free the entry */
             pr1 = &p->prop[h - 1];
+            if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
+                if ((pr->flags & JS_PROP_TMASK) == JS_PROP_VARREF)
+                    if (remove_global_object_property(ctx, p, pr, pr1))
+                        return -1;
+            }
             free_property(ctx->rt, pr1, pr->flags);
             JS_FreeAtom(ctx, pr->atom);
             /* put default values */
@@ -9137,10 +9223,9 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst 
obj,
         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
             return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-            /* JS_PROP_WRITABLE is always true for variable
-               references, but they are write protected in module name
-               spaces. */
-            if (p->class_id == JS_CLASS_MODULE_NS)
+            /* XXX: already use var_ref->is_const. Cannot simplify use the
+               writable flag for JS_CLASS_MODULE_NS. */
+            if (p->class_id == JS_CLASS_MODULE_NS || pr->u.var_ref->is_const)
                 goto read_only_prop;
             set_value(ctx, pr->u.var_ref->pvalue, val);
             return TRUE;
@@ -9299,6 +9384,8 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst 
obj,
                 goto generic_create_prop;
             }
         } else {
+            if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT))
+                goto generic_create_prop;
             pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
             if (unlikely(!pr)) {
                 JS_FreeValue(ctx, val);
@@ -9533,7 +9620,9 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
 {
     JSProperty *pr;
     int ret, prop_flags;
-
+    JSVarRef *var_ref;
+    JSObject *delete_obj;
+    
     /* add a new property or modify an existing exotic one */
     if (p->is_exotic) {
         if (p->class_id == JS_CLASS_ARRAY) {
@@ -9608,15 +9697,37 @@ static int JS_CreateProperty(JSContext *ctx, JSObject 
*p,
         return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not 
extensible");
     }
 
+    var_ref = NULL;
+    delete_obj = NULL;
     if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
         prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
             JS_PROP_GETSET;
     } else {
         prop_flags = flags & JS_PROP_C_W_E;
+        if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
+            JSObject *p1 = 
JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
+            JSShapeProperty *prs1;
+            JSProperty *pr1;
+            prs1 = find_own_property(&pr1, p1, prop);
+            if (prs1) {
+                delete_obj = p1;
+                var_ref = pr1->u.var_ref;
+                var_ref->header.ref_count++;
+            } else {
+                var_ref = js_create_var_ref(ctx, FALSE);
+                if (!var_ref)
+                    return -1;
+            }
+            var_ref->is_const = !(prop_flags & JS_PROP_WRITABLE);
+            prop_flags |= JS_PROP_VARREF;
+        }
     }
     pr = add_property(ctx, p, prop, prop_flags);
-    if (unlikely(!pr))
+    if (unlikely(!pr)) {
+        if (var_ref)
+            free_var_ref(ctx->rt, var_ref);
         return -1;
+    }
     if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
         pr->u.getset.getter = NULL;
         if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
@@ -9628,6 +9739,15 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
             pr->u.getset.setter =
                 JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
         }
+    } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
+        if (delete_obj)
+            delete_property(ctx, delete_obj, prop);
+        pr->u.var_ref = var_ref;
+        if (flags & JS_PROP_HAS_VALUE) {
+            *var_ref->pvalue = JS_DupValue(ctx, val);
+        } else {
+            *var_ref->pvalue = JS_UNDEFINED;
+        }
     } else {
         if (flags & JS_PROP_HAS_VALUE) {
             pr->u.value = JS_DupValue(ctx, val);
@@ -9782,6 +9902,10 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst 
this_obj,
                         return -1;
                     /* convert to getset */
                     if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+                        if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
+                            if (remove_global_object_property(ctx, p, prs, pr))
+                                return -1;
+                        }
                         free_var_ref(ctx->rt, pr->u.var_ref);
                     } else {
                         JS_FreeValue(ctx, pr->u.value);
@@ -9820,14 +9944,31 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst 
this_obj,
             } else {
                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
                     /* convert to data descriptor */
-                    if (js_shape_prepare_update(ctx, p, &prs))
+                    JSVarRef *var_ref;
+                    if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
+                        var_ref = js_global_object_find_uninitialized_var(ctx, 
p, prop, FALSE);
+                        if (!var_ref)
+                            return -1;
+                    } else {
+                        var_ref = NULL;
+                    }
+                    if (js_shape_prepare_update(ctx, p, &prs)) {
+                        if (var_ref)
+                            free_var_ref(ctx->rt, var_ref);
                         return -1;
+                    }
                     if (pr->u.getset.getter)
                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, 
pr->u.getset.getter));
                     if (pr->u.getset.setter)
                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, 
pr->u.getset.setter));
-                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
-                    pr->u.value = JS_UNDEFINED;
+                    if (var_ref) {
+                        prs->flags = (prs->flags & ~JS_PROP_TMASK) |
+                            JS_PROP_VARREF | JS_PROP_WRITABLE;
+                        pr->u.var_ref = var_ref;
+                    } else {
+                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
+                        pr->u.value = JS_UNDEFINED;
+                    }
                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
                     /* Note: JS_PROP_VARREF is always writable */
                 } else {
@@ -9854,8 +9995,6 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst 
this_obj,
                                       JS_DupValue(ctx, val));
                         }
                     }
-                    /* if writable is set to false, no longer a
-                       reference (for mapped arguments) */
                     if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == 
JS_PROP_HAS_WRITABLE) {
                         JSValue val1;
                         if (p->class_id == JS_CLASS_MODULE_NS) {
@@ -9863,10 +10002,17 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst 
this_obj,
                         }
                         if (js_shape_prepare_update(ctx, p, &prs))
                             return -1;
-                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
-                        free_var_ref(ctx->rt, pr->u.var_ref);
-                        pr->u.value = val1;
-                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
+                        if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
+                            pr->u.var_ref->is_const = TRUE; /* mark as 
read-only */
+                            prs->flags &= ~JS_PROP_WRITABLE;
+                        } else {
+                            /* if writable is set to false, no longer a
+                               reference (for mapped arguments) */
+                            val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
+                            free_var_ref(ctx->rt, pr->u.var_ref);
+                            pr->u.value = val1;
+                            prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
+                        }
                     }
                 } else if (prs->flags & JS_PROP_LENGTH) {
                     if (flags & JS_PROP_HAS_VALUE) {
@@ -10199,91 +10345,6 @@ static int JS_CheckDefineGlobalVar(JSContext *ctx, 
JSAtom prop, int flags)
     return 0;
 }
 
-/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
-   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
-/* XXX: could support exotic global object. */
-static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSValue val;
-    int flags;
-
-    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
-        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
-            JS_PROP_CONFIGURABLE;
-        val = JS_UNINITIALIZED;
-    } else {
-        p = JS_VALUE_GET_OBJ(ctx->global_obj);
-        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
-            (def_flags & JS_PROP_CONFIGURABLE);
-        val = JS_UNDEFINED;
-    }
-    prs = find_own_property1(p, prop);
-    if (prs)
-        return 0;
-    if (!p->extensible)
-        return 0;
-    pr = add_property(ctx, p, prop, flags);
-    if (unlikely(!pr))
-        return -1;
-    pr->u.value = val;
-    return 0;
-}
-
-/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
-/* XXX: could support exotic global object. */
-static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
-                                   JSValueConst func, int def_flags)
-{
-
-    JSObject *p;
-    JSShapeProperty *prs;
-    int flags;
-
-    p = JS_VALUE_GET_OBJ(ctx->global_obj);
-    prs = find_own_property1(p, prop);
-    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
-    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
-        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
-            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | 
JS_PROP_HAS_ENUMERABLE;
-    }
-    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
-                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
-        return -1;
-    return 0;
-}
-
-static inline JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
-                                      BOOL throw_ref_error)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* XXX: should handle JS_PROP_TMASK properties */
-        if (unlikely(JS_IsUninitialized(pr->u.value)))
-            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-        return JS_DupValue(ctx, pr->u.value);
-    }
-
-    /* fast path */
-    p = JS_VALUE_GET_OBJ(ctx->global_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        if (likely((prs->flags & JS_PROP_TMASK) == 0))
-            return JS_DupValue(ctx, pr->u.value);
-    }
-    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
-                                 ctx->global_obj, throw_ref_error);
-}
-
 /* construct a reference to a global variable */
 static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
 {
@@ -10295,10 +10356,9 @@ static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom 
prop, JSValue *sp)
     p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
     prs = find_own_property(&pr, p, prop);
     if (prs) {
-        /* XXX: should handle JS_PROP_AUTOINIT properties? */
         /* XXX: conformance: do these tests in
            OP_put_var_ref/OP_get_var_ref ? */
-        if (unlikely(JS_IsUninitialized(pr->u.value))) {
+        if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
             JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
             return -1;
         }
@@ -10321,62 +10381,6 @@ static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom 
prop, JSValue *sp)
     return 0;
 }
 
-/* flag = 0: normal variable write
-   flag = 1: initialize lexical variable
-*/
-static inline int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
-                                  int flag)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    int ret;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* XXX: should handle JS_PROP_AUTOINIT properties? */
-        if (flag != 1) {
-            if (unlikely(JS_IsUninitialized(pr->u.value))) {
-                JS_FreeValue(ctx, val);
-                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                return -1;
-            }
-            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
-                JS_FreeValue(ctx, val);
-                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
-            }
-        }
-        set_value(ctx, &pr->u.value, val);
-        return 0;
-    }
-    
-    p = JS_VALUE_GET_OBJ(ctx->global_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
-                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
-            /* fast path */
-            set_value(ctx, &pr->u.value, val);
-            return 0;
-        }
-    }
-    /* slow path */
-    ret = JS_HasProperty(ctx, ctx->global_obj, prop);
-    if (ret < 0) {
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    if (ret == 0 && is_strict_mode(ctx)) {
-        JS_FreeValue(ctx, val);
-        JS_ThrowReferenceErrorNotDefined(ctx, prop);
-        return -1;
-    }
-    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, 
ctx->global_obj,
-                                  JS_PROP_THROW_STRICT);
-}
-
 /* return -1, FALSE or TRUE */
 static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)
 {
@@ -13956,6 +13960,13 @@ static __maybe_unused void print_atom(JSContext *ctx, 
JSAtom atom)
     js_print_atom(s, atom);
 }
 
+static __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom 
atom)
+{
+    printf("%s=", str);
+    print_atom(ctx, atom);
+    printf("\n");
+}
+
 static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, 
JSValueConst val)
 {
     printf("%s=", str);
@@ -16483,6 +16494,25 @@ static JSValueConst JS_GetActiveFunction(JSContext 
*ctx)
     return ctx->rt->current_stack_frame->cur_func;
 }
 
+static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical)
+{
+    JSVarRef *var_ref;
+    var_ref = js_malloc(ctx, sizeof(JSVarRef));
+    if (!var_ref)
+        return NULL;
+    var_ref->header.ref_count = 1;
+    if (is_lexical)
+        var_ref->value = JS_UNINITIALIZED;
+    else
+        var_ref->value = JS_UNDEFINED;
+    var_ref->pvalue = &var_ref->value;
+    var_ref->is_detached = TRUE;
+    var_ref->is_lexical = FALSE;
+    var_ref->is_const = FALSE;
+    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+    return var_ref;
+}
+
 static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
                              int var_idx, BOOL is_arg)
 {
@@ -16509,6 +16539,8 @@ static JSVarRef *get_var_ref(JSContext *ctx, 
JSStackFrame *sf,
     var_ref->header.ref_count = 1;
     add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
     var_ref->is_detached = FALSE;
+    var_ref->is_lexical = FALSE;
+    var_ref->is_const = FALSE;
     list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
     if (sf->js_mode & JS_MODE_ASYNC) {
         /* The stack frame is detached and may be destroyed at any
@@ -16528,10 +16560,212 @@ static JSVarRef *get_var_ref(JSContext *ctx, 
JSStackFrame *sf,
     return var_ref;
 }
 
+static void js_global_object_finalizer(JSRuntime *rt, JSValue obj)
+{
+    JSObject *p = JS_VALUE_GET_OBJ(obj);
+    JS_FreeValueRT(rt, p->u.global_object.uninitialized_vars);
+}
+
+static void js_global_object_mark(JSRuntime *rt, JSValueConst val,
+                                  JS_MarkFunc *mark_func)
+{
+    JSObject *p = JS_VALUE_GET_OBJ(val);
+    JS_MarkValue(rt, p->u.global_object.uninitialized_vars, mark_func);
+}
+
+static JSVarRef *js_global_object_get_uninitialized_var(JSContext *ctx, 
JSObject *p1, 
+                                                        JSAtom atom)
+{
+    JSObject *p = JS_VALUE_GET_OBJ(p1->u.global_object.uninitialized_vars);
+    JSShapeProperty *prs;
+    JSProperty *pr;
+    JSVarRef *var_ref;
+    
+    prs = find_own_property(&pr, p, atom);
+    if (prs) {
+        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
+        var_ref = pr->u.var_ref;
+        var_ref->header.ref_count++;
+        return var_ref;
+    }
+
+    var_ref = js_create_var_ref(ctx, TRUE);
+    if (!var_ref)
+        return NULL;
+    pr = add_property(ctx, p, atom, JS_PROP_C_W_E | JS_PROP_VARREF);
+    if (unlikely(!pr)) {
+        free_var_ref(ctx->rt, var_ref);
+        return NULL;
+    }
+    pr->u.var_ref = var_ref;
+    var_ref->header.ref_count++;
+    return var_ref;
+}
+
+/* return a new variable reference. Get it from the uninitialized
+   variables if it is present. Return NULL in case of memory error. */
+static JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, 
JSObject *p,
+                                                         JSAtom atom, BOOL 
is_lexical)
+{
+    JSObject *p1;
+    JSShapeProperty *prs;
+    JSProperty *pr;
+    JSVarRef *var_ref;
+    
+    p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
+    prs = find_own_property(&pr, p1, atom);
+    if (prs) {
+        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
+        var_ref = pr->u.var_ref;
+        var_ref->header.ref_count++;
+        delete_property(ctx, p1, atom);
+        if (!is_lexical)
+            var_ref->value = JS_UNDEFINED;
+    } else {
+        var_ref = js_create_var_ref(ctx, is_lexical);
+        if (!var_ref)
+            return NULL;
+    }
+    return var_ref;
+}
+
+static JSVarRef *js_closure_define_global_var(JSContext *ctx, JSClosureVar *cv,
+                                              BOOL is_direct_or_indirect_eval)
+{
+    JSObject *p, *p1;
+    JSShapeProperty *prs;
+    int flags;
+    JSProperty *pr;
+    JSVarRef *var_ref;
+    
+    if (cv->is_lexical) {
+        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+        flags = JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE;
+        if (!cv->is_const)
+            flags |= JS_PROP_WRITABLE;
+
+        prs = find_own_property(&pr, p, cv->var_name);
+        if (prs) {
+            assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
+            var_ref = pr->u.var_ref;
+            var_ref->header.ref_count++;
+            return var_ref;
+        }
+
+        /* if there is a corresponding global variable, reuse its
+           reference and create a new one for the global variable */
+        p1 = JS_VALUE_GET_OBJ(ctx->global_obj);
+        prs = find_own_property(&pr, p1, cv->var_name);
+        if (prs && (prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+            JSVarRef *var_ref1;
+            var_ref1 = js_create_var_ref(ctx, FALSE);
+            if (!var_ref1)
+                return NULL;
+            var_ref = pr->u.var_ref;
+            var_ref1->value = var_ref->value;
+            var_ref->value = JS_UNINITIALIZED;
+            pr->u.var_ref = var_ref1;
+            goto add_var_ref;
+        }
+    } else {
+        p = JS_VALUE_GET_OBJ(ctx->global_obj);
+        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE;
+        if (is_direct_or_indirect_eval)
+            flags |= JS_PROP_CONFIGURABLE;
+
+        prs = find_own_property(&pr, p, cv->var_name);
+        if (prs) {
+            if ((prs->flags & JS_PROP_TMASK) != JS_PROP_VARREF) {
+                var_ref = js_global_object_get_uninitialized_var(ctx, p, 
cv->var_name);
+                if (!var_ref)
+                    return NULL;
+            } else {
+                var_ref = pr->u.var_ref;
+                var_ref->header.ref_count++;
+            }
+            if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL &&
+                (prs->flags & JS_PROP_CONFIGURABLE)) {
+                /* update the property flags if possible when
+                   declaring a global function */
+                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+                    free_property(ctx->rt, pr, prs->flags);
+                    prs->flags = flags | JS_PROP_VARREF;
+                    pr->u.var_ref = var_ref;
+                    var_ref->header.ref_count++;
+                } else {
+                    assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
+                    prs->flags = (prs->flags & ~JS_PROP_C_W_E) | flags;
+                }
+                var_ref->is_const = FALSE;
+            }
+            return var_ref;
+        }
+        
+        if (!p->extensible) {
+            return js_global_object_get_uninitialized_var(ctx, p, 
cv->var_name);
+        }
+    }
+    
+    /* if there is a corresponding uninitialized variable, use it */
+    p1 = JS_VALUE_GET_OBJ(ctx->global_obj);
+    var_ref = js_global_object_find_uninitialized_var(ctx, p1, cv->var_name, 
cv->is_lexical);
+    if (!var_ref)
+        return NULL;
+ add_var_ref:
+    if (cv->is_lexical) {
+        var_ref->is_lexical = TRUE;
+        var_ref->is_const = cv->is_const;
+    }
+
+    pr = add_property(ctx, p, cv->var_name, flags | JS_PROP_VARREF);
+    if (unlikely(!pr)) {
+        free_var_ref(ctx->rt, var_ref);
+        return NULL;
+    }
+    pr->u.var_ref = var_ref;
+    var_ref->header.ref_count++;
+    return var_ref;
+}
+
+static JSVarRef *js_closure_global_var(JSContext *ctx, JSClosureVar *cv)
+{
+    JSObject *p;
+    JSShapeProperty *prs;
+    JSProperty *pr;
+    JSVarRef *var_ref;
+    
+    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+    prs = find_own_property(&pr, p, cv->var_name);
+    if (prs) {
+        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
+        var_ref = pr->u.var_ref;
+        var_ref->header.ref_count++;
+        return var_ref;
+    }
+    p = JS_VALUE_GET_OBJ(ctx->global_obj);
+ redo:
+    prs = find_own_property(&pr, p, cv->var_name);
+    if (prs) {
+        if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT)) {
+            /* Instantiate property and retry */
+            if (JS_AutoInitProperty(ctx, p, cv->var_name, pr, prs))
+                return NULL;
+            goto redo;
+        }
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+            var_ref = pr->u.var_ref;
+            var_ref->header.ref_count++;
+            return var_ref;
+        }
+    }
+    return js_global_object_get_uninitialized_var(ctx, p, cv->var_name);
+}
+
 static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
                            JSFunctionBytecode *b,
                            JSVarRef **cur_var_refs,
-                           JSStackFrame *sf)
+                           JSStackFrame *sf,
+                           BOOL is_eval, JSModuleDef *m)
 {
     JSObject *p;
     JSVarRef **var_refs;
@@ -16546,18 +16780,56 @@ static JSValue js_closure2(JSContext *ctx, JSValue 
func_obj,
         if (!var_refs)
             goto fail;
         p->u.func.var_refs = var_refs;
+        if (is_eval) {
+            /* first pass to check the global variable definitions */
+            for(i = 0; i < b->closure_var_count; i++) {
+                JSClosureVar *cv = &b->closure_var[i];
+                if (cv->closure_type == JS_CLOSURE_GLOBAL_DECL) {
+                    int flags;
+                    flags = 0;
+                    if (cv->is_lexical)
+                        flags |= DEFINE_GLOBAL_LEX_VAR;
+                    if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL)
+                        flags |= DEFINE_GLOBAL_FUNC_VAR;
+                    if (JS_CheckDefineGlobalVar(ctx, cv->var_name, flags))
+                        goto fail;
+                }
+            }
+        }
         for(i = 0; i < b->closure_var_count; i++) {
             JSClosureVar *cv = &b->closure_var[i];
             JSVarRef *var_ref;
-            if (cv->is_local) {
+            switch(cv->closure_type) {
+            case JS_CLOSURE_MODULE_IMPORT:
+                /* imported from other modules */
+                continue;
+            case JS_CLOSURE_MODULE_DECL:
+                var_ref = js_create_var_ref(ctx, cv->is_lexical);
+                break;
+            case JS_CLOSURE_GLOBAL_DECL:
+                var_ref = js_closure_define_global_var(ctx, cv, 
b->is_direct_or_indirect_eval);
+                break;
+            case JS_CLOSURE_GLOBAL:
+                var_ref = js_closure_global_var(ctx, cv);
+                break;
+            case JS_CLOSURE_LOCAL:
                 /* reuse the existing variable reference if it already exists 
*/
-                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
-                if (!var_ref)
-                    goto fail;
-            } else {
+                var_ref = get_var_ref(ctx, sf, cv->var_idx, FALSE);
+                break;
+            case JS_CLOSURE_ARG:
+                /* reuse the existing variable reference if it already exists 
*/
+                var_ref = get_var_ref(ctx, sf, cv->var_idx, TRUE);
+                break;
+            case JS_CLOSURE_REF:
+            case JS_CLOSURE_GLOBAL_REF:
                 var_ref = cur_var_refs[cv->var_idx];
                 var_ref->header.ref_count++;
+                break;
+            default:
+                abort();
             }
+            if (!var_ref)
+                goto fail;
             var_refs[i] = var_ref;
         }
     }
@@ -16598,7 +16870,7 @@ static const uint16_t func_kind_to_class_id[] = {
 
 static JSValue js_closure(JSContext *ctx, JSValue bfunc,
                           JSVarRef **cur_var_refs,
-                          JSStackFrame *sf)
+                          JSStackFrame *sf, BOOL is_eval)
 {
     JSFunctionBytecode *b;
     JSValue func_obj;
@@ -16610,7 +16882,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
         JS_FreeValue(ctx, bfunc);
         return JS_EXCEPTION;
     }
-    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
+    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf, is_eval, NULL);
     if (JS_IsException(func_obj)) {
         /* bfunc has been freed */
         goto fail;
@@ -16697,7 +16969,7 @@ static int js_op_define_class(JSContext *ctx, JSValue 
*sp,
                                   JS_CLASS_BYTECODE_FUNCTION);
     if (JS_IsException(ctor))
         goto fail;
-    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
+    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf, FALSE, NULL);
     bfunc = JS_UNDEFINED;
     if (JS_IsException(ctor))
         goto fail;
@@ -17130,7 +17402,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, 
JSValueConst func_obj,
             *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
             BREAK;
         CASE(OP_fclosure8):
-            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), 
var_refs, sf);
+            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), 
var_refs, sf, FALSE);
             if (unlikely(JS_IsException(sp[-1])))
                 goto exception;
             BREAK;
@@ -17384,7 +17656,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, 
JSValueConst func_obj,
             {
                 JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
                 pc += 4;
-                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
+                *sp++ = js_closure(ctx, bfunc, var_refs, sf, FALSE);
                 if (unlikely(JS_IsException(sp[-1])))
                     goto exception;
             }
@@ -17683,74 +17955,72 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, 
JSValueConst func_obj,
         CASE(OP_get_var_undef):
         CASE(OP_get_var):
             {
+                int idx;
                 JSValue val;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-                sf->cur_pc = pc;
-
-                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                *sp++ = val;
+                idx = get_u16(pc);
+                pc += 2;
+                val = *var_refs[idx]->pvalue;
+                if (unlikely(JS_IsUninitialized(val))) {
+                    JSClosureVar *cv = &b->closure_var[idx];
+                    if (cv->is_lexical) {
+                        JS_ThrowReferenceErrorUninitialized(ctx, cv->var_name);
+                        goto exception;
+                    } else {
+                        sf->cur_pc = pc;
+                        sp[0] = JS_GetPropertyInternal(ctx, ctx->global_obj,
+                                                       cv->var_name,
+                                                       ctx->global_obj,
+                                                       opcode - 
OP_get_var_undef);
+                        if (JS_IsException(sp[0]))
+                            goto exception;
+                    }
+                } else {
+                    sp[0] = JS_DupValue(ctx, val);
+                }
+                sp++;
             }
             BREAK;
 
         CASE(OP_put_var):
         CASE(OP_put_var_init):
             {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-                sf->cur_pc = pc;
-
-                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
-                sp--;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_check_define_var):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                sf->cur_pc = pc;
-                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_define_var):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                sf->cur_pc = pc;
-                if (JS_DefineGlobalVar(ctx, atom, flags))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_define_func):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                sf->cur_pc = pc;
-                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
+                int idx, ret;
+                JSVarRef *var_ref;
+                idx = get_u16(pc);
+                pc += 2;
+                var_ref = var_refs[idx];
+                if (unlikely(JS_IsUninitialized(*var_ref->pvalue) ||
+                             var_ref->is_const)) {
+                    JSClosureVar *cv = &b->closure_var[idx];
+                    if (var_ref->is_lexical) {
+                        if (opcode == OP_put_var_init)
+                            goto put_var_ok;
+                        if (JS_IsUninitialized(*var_ref->pvalue))
+                            JS_ThrowReferenceErrorUninitialized(ctx, 
cv->var_name);
+                        else
+                            JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, 
cv->var_name);
+                        goto exception;
+                    } else {
+                        sf->cur_pc = pc;
+                        ret = JS_HasProperty(ctx, ctx->global_obj, 
cv->var_name);
+                        if (ret < 0)
+                            goto exception;
+                        if (ret == 0 && is_strict_mode(ctx)) {
+                            JS_ThrowReferenceErrorNotDefined(ctx, 
cv->var_name);
+                            goto exception;
+                        }
+                        ret = JS_SetPropertyInternal(ctx, ctx->global_obj, 
cv->var_name, sp[-1],
+                                                     ctx->global_obj, 
JS_PROP_THROW_STRICT);
+                        if (ret < 0)
+                            goto exception;
+                    }
+                } else {
+                put_var_ok:
+                   set_value(ctx, var_ref->pvalue, sp[-1]);
+                }
                 sp--;
             }
             BREAK;
-
         CASE(OP_get_loc):
             {
                 int idx;
@@ -19832,7 +20102,7 @@ static JSValue JS_CallConstructorInternal(JSContext 
*ctx,
         goto not_a_function;
     p = JS_VALUE_GET_OBJ(func_obj);
     if (unlikely(!p->is_constructor))
-        return JS_ThrowTypeError(ctx, "not a constructor");
+        return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj);
     if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
         JSClassCall *call_func;
         call_func = ctx->rt->class_array[p->class_id].call;
@@ -24889,18 +25159,19 @@ done:
     return js_parse_expect(s, ']');
 }
 
-/* XXX: remove */
+/* check if scope chain contains a with statement */
 static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
 {
-    /* check if scope chain contains a with statement */
     while (s) {
-        int scope_idx = s->scopes[scope_level].first;
-        while (scope_idx >= 0) {
-            JSVarDef *vd = &s->vars[scope_idx];
-
-            if (vd->var_name == JS_ATOM__with_)
-                return TRUE;
-            scope_idx = vd->scope_next;
+        /* no with in strict mode */
+        if (!(s->js_mode & JS_MODE_STRICT)) {
+            int scope_idx = s->scopes[scope_level].first;
+            while (scope_idx >= 0) {
+                JSVarDef *vd = &s->vars[scope_idx];
+                if (vd->var_name == JS_ATOM__with_)
+                    return TRUE;
+                scope_idx = vd->scope_next;
+            }
         }
         /* check parent scopes */
         scope_level = s->parent_scope_level;
@@ -24933,7 +25204,11 @@ static __exception int get_lvalue(JSParseState *s, int 
*popcode, int *pscope,
         }
         if (name == JS_ATOM_this || name == JS_ATOM_new_target)
             goto invalid_lvalue;
-        depth = 2;  /* will generate OP_get_ref_value */
+        if (has_with_scope(fd, scope)) {
+            depth = 2;  /* will generate OP_get_ref_value */
+        } else {
+            depth = 0;
+        }
         break;
     case OP_get_field:
         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
@@ -24970,16 +25245,22 @@ static __exception int get_lvalue(JSParseState *s, 
int *popcode, int *pscope,
         /* get the value but keep the object/fields on the stack */
         switch(opcode) {
         case OP_scope_get_var:
-            label = new_label(s);
-            if (label < 0)
-                return -1;
-            emit_op(s, OP_scope_make_ref);
-            emit_atom(s, name);
-            emit_u32(s, label);
-            emit_u16(s, scope);
-            update_label(fd, label, 1);
-            emit_op(s, OP_get_ref_value);
-            opcode = OP_get_ref_value;
+            if (depth != 0) {
+                label = new_label(s);
+                if (label < 0)
+                    return -1;
+                emit_op(s, OP_scope_make_ref);
+                emit_atom(s, name);
+                emit_u32(s, label);
+                emit_u16(s, scope);
+                update_label(fd, label, 1);
+                emit_op(s, OP_get_ref_value);
+                opcode = OP_get_ref_value;
+            } else {
+                emit_op(s, OP_scope_get_var);
+                emit_atom(s, name);
+                emit_u16(s, scope);
+            }
             break;
         case OP_get_field:
             emit_op(s, OP_get_field2);
@@ -25004,15 +25285,17 @@ static __exception int get_lvalue(JSParseState *s, 
int *popcode, int *pscope,
     } else {
         switch(opcode) {
         case OP_scope_get_var:
-            label = new_label(s);
-            if (label < 0)
-                return -1;
-            emit_op(s, OP_scope_make_ref);
-            emit_atom(s, name);
-            emit_u32(s, label);
-            emit_u16(s, scope);
-            update_label(fd, label, 1);
-            opcode = OP_get_ref_value;
+            if (depth != 0) {
+                label = new_label(s);
+                if (label < 0)
+                    return -1;
+                emit_op(s, OP_scope_make_ref);
+                emit_atom(s, name);
+                emit_u32(s, label);
+                emit_u16(s, scope);
+                update_label(fd, label, 1);
+                opcode = OP_get_ref_value;
+            }
             break;
         default:
             break;
@@ -25046,6 +25329,21 @@ static void put_lvalue(JSParseState *s, int opcode, 
int scope,
                        BOOL is_let)
 {
     switch(opcode) {
+    case OP_scope_get_var:
+        /* depth = 0 */
+        switch(special) {
+        case PUT_LVALUE_NOKEEP:
+        case PUT_LVALUE_NOKEEP_DEPTH:
+        case PUT_LVALUE_KEEP_SECOND:
+        case PUT_LVALUE_NOKEEP_BOTTOM:
+            break;
+        case PUT_LVALUE_KEEP_TOP:
+            emit_op(s, OP_dup);
+            break;
+        default:
+            abort();
+        }
+        break;
     case OP_get_field:
     case OP_scope_get_private_field:
         /* depth = 1 */
@@ -25117,8 +25415,6 @@ static void put_lvalue(JSParseState *s, int opcode, int 
scope,
 
     switch(opcode) {
     case OP_scope_get_var:  /* val -- */
-        assert(special == PUT_LVALUE_NOKEEP ||
-               special == PUT_LVALUE_NOKEEP_DEPTH);
         emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
         emit_u32(s, name);  /* has refcount */
         emit_u16(s, scope);
@@ -25472,6 +25768,8 @@ static int js_parse_destructuring_element(JSParseState 
*s, int tok, int is_arg,
                     /* swap ref and lvalue object if any */
                     if (prop_name == JS_ATOM_NULL) {
                         switch(depth_lvalue) {
+                        case 0:
+                            break;
                         case 1:
                             /* source prop x -> x source prop */
                             emit_op(s, OP_rot3r);
@@ -25485,9 +25783,13 @@ static int js_parse_destructuring_element(JSParseState 
*s, int tok, int is_arg,
                             emit_op(s, OP_rot5l);
                             emit_op(s, OP_rot5l);
                             break;
+                        default:
+                            abort();
                         }
                     } else {
                         switch(depth_lvalue) {
+                        case 0:
+                            break;
                         case 1:
                             /* source x -> x source */
                             emit_op(s, OP_swap);
@@ -25500,6 +25802,8 @@ static int js_parse_destructuring_element(JSParseState 
*s, int tok, int is_arg,
                             /* source x y z -> x y z source */
                             emit_op(s, OP_rot4l);
                             break;
+                        default:
+                            abort();
                         }
                     }
                 }
@@ -27151,7 +27455,7 @@ static __exception int 
js_parse_assign_expr2(JSParseState *s, int parse_flags)
         }
 
         if (op == '=') {
-            if (opcode == OP_get_ref_value && name == name0) {
+            if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && 
name == name0) {
                 set_object_name(s, name);
             }
         } else {
@@ -27186,11 +27490,14 @@ static __exception int 
js_parse_assign_expr2(JSParseState *s, int parse_flags)
             return -1;
         }
 
-        if (opcode == OP_get_ref_value && name == name0) {
+        if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name 
== name0) {
             set_object_name(s, name);
         }
 
         switch(depth_lvalue) {
+        case 0:
+            emit_op(s, OP_dup);
+            break;
         case 1:
             emit_op(s, OP_insert2);
             break;
@@ -29486,31 +29793,11 @@ static int js_resolve_module(JSContext *ctx, 
JSModuleDef *m)
     return 0;
 }
 
-static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
-{
-    JSVarRef *var_ref;
-    var_ref = js_malloc(ctx, sizeof(JSVarRef));
-    if (!var_ref)
-        return NULL;
-    var_ref->header.ref_count = 1;
-    if (is_lexical)
-        var_ref->value = JS_UNINITIALIZED;
-    else
-        var_ref->value = JS_UNDEFINED;
-    var_ref->pvalue = &var_ref->value;
-    var_ref->is_detached = TRUE;
-    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
-    return var_ref;
-}
-
 /* Create the <eval> function associated with the module */
 static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
 {
     JSFunctionBytecode *b;
-    int i;
-    JSVarRef **var_refs;
     JSValue func_obj, bfunc;
-    JSObject *p;
 
     bfunc = m->func_obj;
     func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
@@ -29519,40 +29806,14 @@ static int 
js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
     if (JS_IsException(func_obj))
         return -1;
     b = JS_VALUE_GET_PTR(bfunc);
-
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->u.func.function_bytecode = b;
-    b->header.ref_count++;
-    p->u.func.home_object = NULL;
-    p->u.func.var_refs = NULL;
-    if (b->closure_var_count) {
-        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
-        if (!var_refs)
-            goto fail;
-        p->u.func.var_refs = var_refs;
-
-        /* create the global variables. The other variables are
-           imported from other modules */
-        for(i = 0; i < b->closure_var_count; i++) {
-            JSClosureVar *cv = &b->closure_var[i];
-            JSVarRef *var_ref;
-            if (cv->is_local) {
-                var_ref = js_create_module_var(ctx, cv->is_lexical);
-                if (!var_ref)
-                    goto fail;
-#ifdef DUMP_MODULE_RESOLVE
-                printf("local %d: %p\n", i, var_ref);
-#endif
-                var_refs[i] = var_ref;
-            }
-        }
+    func_obj = js_closure2(ctx, func_obj, b, NULL, NULL, TRUE, m);
+    if (JS_IsException(func_obj)) {
+        m->func_obj = JS_UNDEFINED; /* XXX: keep it ? */
+        JS_FreeValue(ctx, func_obj);
+        return -1;
     }
     m->func_obj = func_obj;
-    JS_FreeValue(ctx, bfunc);
     return 0;
- fail:
-    JS_FreeValue(ctx, func_obj);
-    return -1;
 }
 
 /* must be done before js_link_module() because of cyclic references */
@@ -29572,7 +29833,7 @@ static int js_create_module_function(JSContext *ctx, 
JSModuleDef *m)
         for(i = 0; i < m->export_entries_count; i++) {
             JSExportEntry *me = &m->export_entries[i];
             if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-                var_ref = js_create_module_var(ctx, FALSE);
+                var_ref = js_create_var_ref(ctx, FALSE);
                 if (!var_ref)
                     return -1;
                 me->u.local.var_ref = var_ref;
@@ -29731,7 +29992,7 @@ static int js_inner_module_linking(JSContext *ctx, 
JSModuleDef *m,
                     val = JS_GetModuleNamespace(ctx, m2);
                     if (JS_IsException(val))
                         goto fail;
-                    var_ref = js_create_module_var(ctx, TRUE);
+                    var_ref = js_create_var_ref(ctx, TRUE);
                     if (!var_ref) {
                         JS_FreeValue(ctx, val);
                         goto fail;
@@ -30835,7 +31096,7 @@ static __exception int js_parse_export(JSParseState *s)
 }
 
 static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           BOOL is_local, BOOL is_arg,
+                           JSClosureTypeEnum closure_type,
                            int var_idx, JSAtom var_name,
                            BOOL is_const, BOOL is_lexical,
                            JSVarKindEnum var_kind);
@@ -30857,9 +31118,10 @@ static int add_import(JSParseState *s, JSModuleDef *m,
         }
     }
 
-    var_idx = add_closure_var(ctx, s->cur_func, is_star, FALSE,
+    var_idx = add_closure_var(ctx, s->cur_func,
+                              is_star ? JS_CLOSURE_MODULE_DECL : 
JS_CLOSURE_MODULE_IMPORT,
                               m->import_entries_count,
-                              local_name, TRUE, TRUE, FALSE);
+                              local_name, TRUE, TRUE, JS_VAR_NORMAL);
     if (var_idx < 0)
         return -1;
     if (js_resize_array(ctx, (void **)&m->import_entries,
@@ -31623,12 +31885,39 @@ static __maybe_unused void 
js_dump_function_bytecode(JSContext *ctx, JSFunctionB
         printf("  closure vars:\n");
         for(i = 0; i < b->closure_var_count; i++) {
             JSClosureVar *cv = &b->closure_var[i];
-            printf("%5d: %s %s:%s%d %s\n", i,
-                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), 
cv->var_name),
-                   cv->is_local ? "local" : "parent",
-                   cv->is_arg ? "arg" : "loc", cv->var_idx,
+            printf("%5d: %s %s", i,
                    cv->is_const ? "const" :
-                   cv->is_lexical ? "let" : "var");
+                   cv->is_lexical ? "let" : "var",
+                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), 
cv->var_name));
+            switch(cv->closure_type) {
+            case JS_CLOSURE_LOCAL:
+                printf(" [loc%d]\n", cv->var_idx);
+                break;
+            case JS_CLOSURE_ARG:
+                printf(" [arg%d]\n", cv->var_idx);
+                break;
+            case JS_CLOSURE_REF:
+                printf(" [ref%d]\n", cv->var_idx);
+                break;
+            case JS_CLOSURE_GLOBAL_REF:
+                printf(" [global_ref%d]\n", cv->var_idx);
+                break;
+            case JS_CLOSURE_GLOBAL_DECL:
+                printf(" [global_decl]\n");
+                break;
+            case JS_CLOSURE_GLOBAL:
+                printf(" [global]\n");
+                break;
+            case JS_CLOSURE_MODULE_DECL:
+                printf(" [module_decl]\n");
+                break;
+            case JS_CLOSURE_MODULE_IMPORT:
+                printf(" [module_import]\n");
+                break;
+            default:
+                printf(" [?]\n");
+                break;
+            }
         }
     }
     printf("  stack_size: %d\n", b->stack_size);
@@ -31649,7 +31938,7 @@ static __maybe_unused void 
js_dump_function_bytecode(JSContext *ctx, JSFunctionB
 #endif
 
 static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           BOOL is_local, BOOL is_arg,
+                           JSClosureTypeEnum closure_type,
                            int var_idx, JSAtom var_name,
                            BOOL is_const, BOOL is_lexical,
                            JSVarKindEnum var_kind)
@@ -31667,8 +31956,7 @@ static int add_closure_var(JSContext *ctx, 
JSFunctionDef *s,
                         &s->closure_var_size, s->closure_var_count + 1))
         return -1;
     cv = &s->closure_var[s->closure_var_count++];
-    cv->is_local = is_local;
-    cv->is_arg = is_arg;
+    cv->closure_type = closure_type;
     cv->is_const = is_const;
     cv->is_lexical = is_lexical;
     cv->var_kind = var_kind;
@@ -31689,46 +31977,34 @@ static int find_closure_var(JSContext *ctx, 
JSFunctionDef *s,
     return -1;
 }
 
-/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
-   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
-   'fd' */
-static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
-                            JSFunctionDef *fd, BOOL is_local,
-                            BOOL is_arg, int var_idx, JSAtom var_name,
-                            BOOL is_const, BOOL is_lexical,
-                            JSVarKindEnum var_kind)
+/* 'fd' must be a parent of 's'. Create in 's' a closure referencing
+   another one in 'fd' */
+static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
+                           JSFunctionDef *fd, JSClosureTypeEnum closure_type,
+                           int var_idx, JSAtom var_name,
+                           BOOL is_const, BOOL is_lexical,
+                           JSVarKindEnum var_kind)
 {
     int i;
 
     if (fd != s->parent) {
-        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
-                                   is_arg, var_idx, var_name,
-                                   is_const, is_lexical, var_kind);
+        var_idx = get_closure_var(ctx, s->parent, fd, closure_type,
+                                  var_idx, var_name,
+                                  is_const, is_lexical, var_kind);
         if (var_idx < 0)
             return -1;
-        is_local = FALSE;
+        if (closure_type != JS_CLOSURE_GLOBAL_REF)
+            closure_type = JS_CLOSURE_REF;
     }
     for(i = 0; i < s->closure_var_count; i++) {
         JSClosureVar *cv = &s->closure_var[i];
-        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
-            cv->is_local == is_local)
+        if (cv->var_idx == var_idx && cv->closure_type == closure_type)
             return i;
     }
-    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
+    return add_closure_var(ctx, s, closure_type, var_idx, var_name,
                            is_const, is_lexical, var_kind);
 }
 
-static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           JSFunctionDef *fd, BOOL is_arg,
-                           int var_idx, JSAtom var_name,
-                           BOOL is_const, BOOL is_lexical,
-                           JSVarKindEnum var_kind)
-{
-    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
-                            var_idx, var_name, is_const, is_lexical,
-                            var_kind);
-}
-
 static int get_with_scope_opcode(int op)
 {
     if (op == OP_scope_get_var_undef)
@@ -31801,41 +32077,6 @@ static int optimize_scope_make_ref(JSContext *ctx, 
JSFunctionDef *s,
     return pos_next;
 }
 
-static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
-                                          DynBuf *bc, uint8_t *bc_buf,
-                                          LabelSlot *ls, int pos_next,
-                                          JSAtom var_name)
-{
-    int label_pos, end_pos, pos, op;
-
-    /* replace the reference get/put with normal variable
-       accesses */
-    /* XXX: need 2 extra OP_true if destructuring an array */
-    if (bc_buf[pos_next] == OP_get_ref_value) {
-        dbuf_putc(bc, OP_get_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        pos_next++;
-    }
-    /* remove the OP_label to make room for replacement */
-    /* label should have a refcount of 0 anyway */
-    /* XXX: should have emitted several OP_nop to avoid this kludge */
-    label_pos = ls->pos;
-    pos = label_pos - 5;
-    assert(bc_buf[pos] == OP_label);
-    end_pos = label_pos + 2;
-    op = bc_buf[label_pos];
-    if (op == OP_insert3)
-        bc_buf[pos++] = OP_dup;
-    bc_buf[pos] = OP_put_var;
-    /* XXX: need 2 extra OP_drop if destructuring an array */
-    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
-    pos += 5;
-    /* pad with OP_nop */
-    while (pos < end_pos)
-        bc_buf[pos++] = OP_nop;
-    return pos_next;
-}
-
 static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
 {
     int idx;
@@ -31909,7 +32150,7 @@ static void var_object_test(JSContext *ctx, 
JSFunctionDef *s,
     s->jump_size++;
 }
 
-/* return the position of the next opcode */
+/* return the position of the next opcode or -1 if error */
 static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
                              JSAtom var_name, int scope_level, int op,
                              DynBuf *bc, uint8_t *bc_buf,
@@ -32028,14 +32269,22 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
                 }
             }
             break;
+        case OP_scope_put_var:
+            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
+                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
+                /* in non strict mode, modifying the function name is ignored 
*/
+                dbuf_putc(bc, OP_drop);
+                goto done;
+            }
+            goto local_scope_var;
         case OP_scope_get_ref:
             dbuf_putc(bc, OP_undefined);
-            /* fall thru */
+            goto local_scope_var;
         case OP_scope_get_var_checkthis:
         case OP_scope_get_var_undef:
         case OP_scope_get_var:
-        case OP_scope_put_var:
         case OP_scope_put_var_init:
+        local_scope_var:
             is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
             if (var_idx & ARGUMENT_VAR_OFFSET) {
                 dbuf_putc(bc, OP_get_arg + is_put);
@@ -32108,7 +32357,7 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
                 break;
             } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
                 vd->is_captured = 1;
-                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, 
FALSE, FALSE, JS_VAR_NORMAL);
+                idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, 
vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
                 if (idx >= 0) {
                     dbuf_putc(bc, OP_get_var_ref);
                     dbuf_put_u16(bc, idx);
@@ -32145,7 +32394,7 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
         if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
             vd = &fd->vars[fd->var_object_idx];
             vd->is_captured = 1;
-            idx = get_closure_var(ctx, s, fd, FALSE,
+            idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
                                   fd->var_object_idx, vd->var_name,
                                   FALSE, FALSE, JS_VAR_NORMAL);
             dbuf_putc(bc, OP_get_var_ref);
@@ -32157,7 +32406,7 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
         if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
             vd = &fd->vars[fd->arg_var_object_idx];
             vd->is_captured = 1;
-            idx = get_closure_var(ctx, s, fd, FALSE,
+            idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
                                   fd->arg_var_object_idx, vd->var_name,
                                   FALSE, FALSE, JS_VAR_NORMAL);
             dbuf_putc(bc, OP_get_var_ref);
@@ -32179,25 +32428,37 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
             JSClosureVar *cv = &fd->closure_var[idx1];
             if (var_name == cv->var_name) {
                 if (fd != s) {
-                    idx = get_closure_var2(ctx, s, fd,
-                                           FALSE,
-                                           cv->is_arg, idx1,
-                                           cv->var_name, cv->is_const,
-                                           cv->is_lexical, cv->var_kind);
+                    JSClosureTypeEnum closure_type;
+                    if (cv->closure_type == JS_CLOSURE_GLOBAL ||
+                        cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
+                        cv->closure_type == JS_CLOSURE_GLOBAL_REF)
+                        closure_type = JS_CLOSURE_GLOBAL_REF;
+                    else
+                        closure_type = JS_CLOSURE_REF;
+                    idx = get_closure_var(ctx, s, fd,
+                                          closure_type,
+                                          idx1,
+                                          cv->var_name, cv->is_const,
+                                          cv->is_lexical, cv->var_kind);
                 } else {
                     idx = idx1;
                 }
-                goto has_idx;
+                if (cv->closure_type == JS_CLOSURE_GLOBAL ||
+                    cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
+                    cv->closure_type == JS_CLOSURE_GLOBAL_REF)
+                    goto has_global_idx;
+                else
+                    goto has_idx;
             } else if ((cv->var_name == JS_ATOM__var_ ||
                         cv->var_name == JS_ATOM__arg_var_ ||
                         cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
                 int is_with = (cv->var_name == JS_ATOM__with_);
                 if (fd != s) {
-                    idx = get_closure_var2(ctx, s, fd,
-                                           FALSE,
-                                           cv->is_arg, idx1,
-                                           cv->var_name, FALSE, FALSE,
-                                           JS_VAR_NORMAL);
+                    idx = get_closure_var(ctx, s, fd,
+                                          JS_CLOSURE_REF,
+                                          idx1,
+                                          cv->var_name, FALSE, FALSE,
+                                          JS_VAR_NORMAL);
                 } else {
                     idx = idx1;
                 }
@@ -32206,19 +32467,67 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
                 var_object_test(ctx, s, var_name, op, bc, &label_done, 
is_with);
             }
         }
-    }
 
-    if (var_idx >= 0) {
+        /* not found: add a closure for a global variable access */
+        idx1 = add_closure_var(ctx, fd, JS_CLOSURE_GLOBAL, 0, var_name,
+                              FALSE, FALSE, JS_VAR_NORMAL);
+        if (idx1 < 0)
+            return -1;
+        if (fd != s) {
+            idx = get_closure_var(ctx, s, fd,
+                                  JS_CLOSURE_GLOBAL_REF,
+                                  idx1,
+                                  var_name, FALSE, FALSE, 
+                                  JS_VAR_NORMAL);
+        } else {
+            idx = idx1;
+        }
+    has_global_idx:
+        /* global variable access */
+        switch (op) {
+        case OP_scope_make_ref:
+            if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, 
ls->pos)) {
+                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
+                                                   pos_next,
+                                                   OP_get_var, idx);
+            } else {
+                dbuf_putc(bc, OP_make_var_ref);
+                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            }
+            break;
+        case OP_scope_get_ref:
+            /* XXX: should create a dummy object with a named slot that is
+               a reference to the global variable */
+            dbuf_putc(bc, OP_undefined);
+            dbuf_putc(bc, OP_get_var);
+            dbuf_put_u16(bc, idx);
+            break;
+        case OP_scope_get_var_undef:
+        case OP_scope_get_var:
+        case OP_scope_put_var:
+            dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
+            dbuf_put_u16(bc, idx);
+            break;
+        case OP_scope_put_var_init:
+            dbuf_putc(bc, OP_put_var_init);
+            dbuf_put_u16(bc, idx);
+            break;
+        case OP_scope_delete_var:
+            dbuf_putc(bc, OP_delete_var);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            break;
+        }
+    } else {
         /* find the corresponding closure variable */
         if (var_idx & ARGUMENT_VAR_OFFSET) {
             fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
             idx = get_closure_var(ctx, s, fd,
-                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
+                                  JS_CLOSURE_ARG, var_idx - 
ARGUMENT_VAR_OFFSET,
                                   var_name, FALSE, FALSE, JS_VAR_NORMAL);
         } else {
             fd->vars[var_idx].is_captured = 1;
             idx = get_closure_var(ctx, s, fd,
-                                  FALSE, var_idx,
+                                  JS_CLOSURE_LOCAL, var_idx,
                                   var_name,
                                   fd->vars[var_idx].is_const,
                                   fd->vars[var_idx].is_lexical,
@@ -32263,15 +32572,22 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
                     dbuf_put_u16(bc, idx);
                 }
                 break;
+            case OP_scope_put_var:
+                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
+                    /* in non strict mode, modifying the function name is 
ignored */
+                    dbuf_putc(bc, OP_drop);
+                    goto done;
+                }
+                goto closure_scope_var;
             case OP_scope_get_ref:
                 /* XXX: should create a dummy object with a named slot that is
                    a reference to the closure variable */
                 dbuf_putc(bc, OP_undefined);
-                /* fall thru */
+                goto closure_scope_var;
             case OP_scope_get_var_undef:
             case OP_scope_get_var:
-            case OP_scope_put_var:
             case OP_scope_put_var_init:
+            closure_scope_var:
                 is_put = (op == OP_scope_put_var ||
                           op == OP_scope_put_var_init);
                 if (is_put) {
@@ -32305,40 +32621,6 @@ static int resolve_scope_var(JSContext *ctx, 
JSFunctionDef *s,
         }
     }
 
-    /* global variable access */
-
-    switch (op) {
-    case OP_scope_make_ref:
-        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) 
{
-            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
-                                                      pos_next, var_name);
-        } else {
-            dbuf_putc(bc, OP_make_var_ref);
-            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        }
-        break;
-    case OP_scope_get_ref:
-        /* XXX: should create a dummy object with a named slot that is
-           a reference to the global variable */
-        dbuf_putc(bc, OP_undefined);
-        dbuf_putc(bc, OP_get_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_get_var_undef:
-    case OP_scope_get_var:
-    case OP_scope_put_var:
-        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_put_var_init:
-        dbuf_putc(bc, OP_put_var_init);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_delete_var:
-        dbuf_putc(bc, OP_delete_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    }
 done:
     if (label_done >= 0) {
         dbuf_putc(bc, OP_label);
@@ -32390,7 +32672,7 @@ static int resolve_scope_private_field1(JSContext *ctx,
         if (idx >= 0) {
             var_kind = fd->vars[idx].var_kind;
             if (is_ref) {
-                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
+                idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, 
var_name,
                                       TRUE, TRUE, JS_VAR_NORMAL);
                 if (idx < 0)
                     return -1;
@@ -32407,12 +32689,12 @@ static int resolve_scope_private_field1(JSContext 
*ctx,
                         var_kind = cv->var_kind;
                         is_ref = TRUE;
                         if (fd != s) {
-                            idx = get_closure_var2(ctx, s, fd,
-                                                   FALSE,
-                                                   cv->is_arg, idx,
-                                                   cv->var_name, cv->is_const,
-                                                   cv->is_lexical,
-                                                   cv->var_kind);
+                            idx = get_closure_var(ctx, s, fd,
+                                                  JS_CLOSURE_REF,
+                                                  idx,
+                                                  cv->var_name, cv->is_const,
+                                                  cv->is_lexical,
+                                                  cv->var_kind);
                             if (idx < 0)
                                 return -1;
                         }
@@ -32641,7 +32923,7 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
         while (scope_idx >= 0) {
             vd = &fd->vars[scope_idx];
             vd->is_captured = 1;
-            get_closure_var(ctx, s, fd, FALSE, scope_idx,
+            get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
                             vd->var_name, vd->is_const, vd->is_lexical, 
vd->var_kind);
             scope_idx = vd->scope_next;
         }
@@ -32653,7 +32935,7 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
                 vd = &fd->args[i];
                 if (vd->var_name != JS_ATOM_NULL) {
                     get_closure_var(ctx, s, fd,
-                                    TRUE, i, vd->var_name, FALSE,
+                                    JS_CLOSURE_ARG, i, vd->var_name, FALSE,
                                     vd->is_lexical, JS_VAR_NORMAL);
                 }
             }
@@ -32664,7 +32946,7 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
                     vd->var_name != JS_ATOM__ret_ &&
                     vd->var_name != JS_ATOM_NULL) {
                     get_closure_var(ctx, s, fd,
-                                    FALSE, i, vd->var_name, FALSE,
+                                    JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
                                     vd->is_lexical, JS_VAR_NORMAL);
                 }
             }
@@ -32674,7 +32956,7 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
                 /* do not close top level last result */
                 if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
                     get_closure_var(ctx, s, fd,
-                                    FALSE, i, vd->var_name, FALSE,
+                                    JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
                                     vd->is_lexical, JS_VAR_NORMAL);
                 }
             }
@@ -32682,13 +32964,19 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
         if (fd->is_eval) {
             int idx;
             /* add direct eval variables (we are necessarily at the
-               top level) */
+               top level). */
             for (idx = 0; idx < fd->closure_var_count; idx++) {
                 JSClosureVar *cv = &fd->closure_var[idx];
-                get_closure_var2(ctx, s, fd,
-                                 FALSE, cv->is_arg,
-                                 idx, cv->var_name, cv->is_const,
-                                 cv->is_lexical, cv->var_kind);
+                /* Global variables are removed but module
+                   definitions are kept. */
+                if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&
+                    cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&
+                    cv->closure_type != JS_CLOSURE_GLOBAL) {
+                    get_closure_var(ctx, s, fd,
+                                    JS_CLOSURE_REF,
+                                    idx, cv->var_name, cv->is_const,
+                                    cv->is_lexical, cv->var_kind);
+                }
             }
         }
     }
@@ -32697,8 +32985,7 @@ static void add_eval_variables(JSContext *ctx, 
JSFunctionDef *s)
 static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
                                  JSVarDef *vd, int var_idx)
 {
-    cv->is_local = TRUE;
-    cv->is_arg = FALSE;
+    cv->closure_type = JS_CLOSURE_LOCAL;
     cv->is_const = vd->is_const;
     cv->is_lexical = vd->is_lexical;
     cv->var_kind = vd->var_kind;
@@ -32739,8 +33026,7 @@ static __exception int add_closure_variables(JSContext 
*ctx, JSFunctionDef *s,
         for(i = 0; i < b->arg_count; i++) {
             JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
             vd = &b->vardefs[i];
-            cv->is_local = TRUE;
-            cv->is_arg = TRUE;
+            cv->closure_type = JS_CLOSURE_ARG;
             cv->is_const = FALSE;
             cv->is_lexical = FALSE;
             cv->var_kind = JS_VAR_NORMAL;
@@ -32767,9 +33053,24 @@ static __exception int add_closure_variables(JSContext 
*ctx, JSFunctionDef *s,
     }
     for(i = 0; i < b->closure_var_count; i++) {
         JSClosureVar *cv0 = &b->closure_var[i];
-        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-        cv->is_local = FALSE;
-        cv->is_arg = cv0->is_arg;
+        JSClosureVar *cv;
+
+        switch(cv0->closure_type) {
+        case JS_CLOSURE_LOCAL:
+        case JS_CLOSURE_ARG:
+        case JS_CLOSURE_REF:
+        case JS_CLOSURE_MODULE_DECL:
+        case JS_CLOSURE_MODULE_IMPORT:
+            break;
+        case JS_CLOSURE_GLOBAL_REF:
+        case JS_CLOSURE_GLOBAL_DECL:
+        case JS_CLOSURE_GLOBAL:
+            continue; /* not necessary to add global variables */
+        default:
+            abort();
+        }
+        cv = &s->closure_var[s->closure_var_count++];
+        cv->closure_type = JS_CLOSURE_REF;
         cv->is_const = cv0->is_const;
         cv->is_lexical = cv0->is_lexical;
         cv->var_kind = cv0->var_kind;
@@ -32962,9 +33263,10 @@ static void instantiate_hoisted_definitions(JSContext 
*ctx, JSFunctionDef *s, Dy
 
     /* add the global variables (only happens if s->is_global_var is
        true) */
+    /* XXX: inefficient, add a closure index in JSGlobalVar */
     for(i = 0; i < s->global_var_count; i++) {
         JSGlobalVar *hf = &s->global_vars[i];
-        int has_closure = 0;
+        BOOL has_var_obj = FALSE;
         BOOL force_init = hf->force_init;
         /* we are in an eval, so the closure contains all the
            enclosing variables */
@@ -32973,46 +33275,20 @@ static void instantiate_hoisted_definitions(JSContext 
*ctx, JSFunctionDef *s, Dy
         for(idx = 0; idx < s->closure_var_count; idx++) {
             JSClosureVar *cv = &s->closure_var[idx];
             if (cv->var_name == hf->var_name) {
-                has_closure = 2;
                 force_init = FALSE;
-                break;
+                goto closure_found;
             }
             if (cv->var_name == JS_ATOM__var_ ||
                 cv->var_name == JS_ATOM__arg_var_) {
                 dbuf_putc(bc, OP_get_var_ref);
                 dbuf_put_u16(bc, idx);
-                has_closure = 1;
+                has_var_obj = TRUE;
                 force_init = TRUE;
-                break;
-            }
-        }
-        if (!has_closure) {
-            int flags;
-
-            flags = 0;
-            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
-                flags |= JS_PROP_CONFIGURABLE;
-            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
-                /* global function definitions need a specific handling */
-                dbuf_putc(bc, OP_fclosure);
-                dbuf_put_u32(bc, hf->cpool_idx);
-
-                dbuf_putc(bc, OP_define_func);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-                dbuf_putc(bc, flags);
-
-                goto done_global_var;
-            } else {
-                if (hf->is_lexical) {
-                    flags |= DEFINE_GLOBAL_LEX_VAR;
-                    if (!hf->is_const)
-                        flags |= JS_PROP_WRITABLE;
-                }
-                dbuf_putc(bc, OP_define_var);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-                dbuf_putc(bc, flags);
+                goto closure_found;
             }
         }
+        abort();
+    closure_found:
         if (hf->cpool_idx >= 0 || force_init) {
             if (hf->cpool_idx >= 0) {
                 dbuf_putc(bc, OP_fclosure);
@@ -33025,20 +33301,15 @@ static void instantiate_hoisted_definitions(JSContext 
*ctx, JSFunctionDef *s, Dy
             } else {
                 dbuf_putc(bc, OP_undefined);
             }
-            if (has_closure == 2) {
+            if (!has_var_obj) {
                 dbuf_putc(bc, OP_put_var_ref);
                 dbuf_put_u16(bc, idx);
-            } else if (has_closure == 1) {
+            } else {
                 dbuf_putc(bc, OP_define_field);
                 dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
                 dbuf_putc(bc, OP_drop);
-            } else {
-                /* XXX: Check if variable is writable and enumerable */
-                dbuf_putc(bc, OP_put_var);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
             }
         }
-    done_global_var:
         JS_FreeAtom(ctx, hf->var_name);
     }
 
@@ -33133,7 +33404,7 @@ static int get_label_pos(JSFunctionDef *s, int label)
    variables when necessary */
 static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
 {
-    int pos, pos_next, bc_len, op, len, i, idx, line_num;
+    int pos, pos_next, bc_len, op, len, line_num, i, idx;
     uint8_t *bc_buf;
     JSAtom var_name;
     DynBuf bc_out;
@@ -33146,13 +33417,19 @@ static __exception int resolve_variables(JSContext 
*ctx, JSFunctionDef *s)
 
     /* first pass for runtime checks (must be done before the
        variables are created) */
+    /* XXX: inefficient */
     for(i = 0; i < s->global_var_count; i++) {
         JSGlobalVar *hf = &s->global_vars[i];
-        int flags;
 
         /* check if global variable (XXX: simplify) */
         for(idx = 0; idx < s->closure_var_count; idx++) {
             JSClosureVar *cv = &s->closure_var[idx];
+            if (cv->closure_type == JS_CLOSURE_GLOBAL_REF ||
+                cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
+                cv->closure_type == JS_CLOSURE_GLOBAL ||
+                cv->closure_type == JS_CLOSURE_MODULE_DECL ||
+                cv->closure_type == JS_CLOSURE_MODULE_IMPORT)
+                goto next; /* don't look at global variables (they are at the 
end) */
             if (cv->var_name == hf->var_name) {
                 if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
                     cv->is_lexical) {
@@ -33171,15 +33448,6 @@ static __exception int resolve_variables(JSContext 
*ctx, JSFunctionDef *s)
                 cv->var_name == JS_ATOM__arg_var_)
                 goto next;
         }
-
-        dbuf_putc(&bc_out, OP_check_define_var);
-        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
-        flags = 0;
-        if (hf->is_lexical)
-            flags |= DEFINE_GLOBAL_LEX_VAR;
-        if (hf->cpool_idx >= 0)
-            flags |= DEFINE_GLOBAL_FUNC_VAR;
-        dbuf_putc(&bc_out, flags);
     next: ;
     }
 
@@ -34895,35 +35163,68 @@ static __exception int compute_stack_size(JSContext 
*ctx,
     return -1;
 }
 
-static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
+static int add_global_variables(JSContext *ctx, JSFunctionDef *fd)
 {
     int i, idx;
     JSModuleDef *m = fd->module;
     JSExportEntry *me;
     JSGlobalVar *hf;
+    BOOL need_global_closures;
+    
+    /* Script: add the defined global variables. In the non strict
+       direct eval not in global scope, the global variables are
+       created in the enclosing scope so they are not created as
+       variable references.
 
-    /* The imported global variables were added as closure variables
-       in js_parse_import(). We add here the module global
-       variables. */
-
-    for(i = 0; i < fd->global_var_count; i++) {
-        hf = &fd->global_vars[i];
-        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, 
hf->is_const,
-                            hf->is_lexical, FALSE) < 0)
-            return -1;
+       In modules, the imported global variables were added as closure
+       global variables in js_parse_import().
+    */
+    need_global_closures = TRUE;
+    if (fd->eval_type == JS_EVAL_TYPE_DIRECT && !(fd->js_mode & 
JS_MODE_STRICT)) {
+        /* XXX: add a flag ? */
+        for(idx = 0; idx < fd->closure_var_count; idx++) {
+            JSClosureVar *cv = &fd->closure_var[idx];
+            if (cv->var_name == JS_ATOM__var_ ||
+                cv->var_name == JS_ATOM__arg_var_) {
+                need_global_closures = FALSE;
+                break;
+            }
+        }
     }
 
-    /* resolve the variable names of the local exports */
-    for(i = 0; i < m->export_entries_count; i++) {
-        me = &m->export_entries[i];
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-            idx = find_closure_var(ctx, fd, me->local_name);
-            if (idx < 0) {
-                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not 
exist",
-                                        me->local_name);
+    if (need_global_closures) {
+        JSClosureTypeEnum closure_type;
+        if (fd->module)
+            closure_type = JS_CLOSURE_MODULE_DECL;
+        else
+            closure_type = JS_CLOSURE_GLOBAL_DECL;
+        for(i = 0; i < fd->global_var_count; i++) {
+            JSVarKindEnum var_kind;
+            hf = &fd->global_vars[i];
+            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
+                var_kind = JS_VAR_GLOBAL_FUNCTION_DECL;
+            } else {
+                var_kind = JS_VAR_NORMAL;
+            }
+            if (add_closure_var(ctx, fd, closure_type, i, hf->var_name, 
hf->is_const,
+                                hf->is_lexical, var_kind) < 0)
                 return -1;
+        }
+    }
+
+    if (fd->module) {
+        /* resolve the variable names of the local exports */
+        for(i = 0; i < m->export_entries_count; i++) {
+            me = &m->export_entries[i];
+            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+                idx = find_closure_var(ctx, fd, me->local_name);
+                if (idx < 0) {
+                    JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does 
not exist",
+                                            me->local_name);
+                    return -1;
+                }
+                me->u.local.var_idx = idx;
             }
-            me->u.local.var_idx = idx;
         }
     }
     return 0;
@@ -34975,10 +35276,10 @@ static JSValue js_create_function(JSContext *ctx, 
JSFunctionDef *fd)
         add_eval_variables(ctx, fd);
 
     /* add the module global variables in the closure */
-    if (fd->module) {
-        if (add_module_variables(ctx, fd))
+    if (fd->is_eval) {
+        if (add_global_variables(ctx, fd))
             goto fail;
-    }
+    } 
 
     /* first create all the child functions */
     list_for_each_safe(el, el1, &fd->child_list) {
@@ -36031,7 +36332,9 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, 
JSValue fun_obj,
 
     tag = JS_VALUE_GET_TAG(fun_obj);
     if (tag == JS_TAG_FUNCTION_BYTECODE) {
-        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
+        fun_obj = js_closure(ctx, fun_obj, var_refs, sf, TRUE);
+        if (JS_IsException(fun_obj))
+            return JS_EXCEPTION;
         ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
     } else if (tag == JS_TAG_MODULE) {
         JSModuleDef *m;
@@ -36755,13 +37058,12 @@ static int JS_WriteFunctionTag(BCWriterState *s, 
JSValueConst obj)
         bc_put_atom(s, cv->var_name);
         bc_put_leb128(s, cv->var_idx);
         flags = idx = 0;
-        bc_set_flags(&flags, &idx, cv->is_local, 1);
-        bc_set_flags(&flags, &idx, cv->is_arg, 1);
+        bc_set_flags(&flags, &idx, cv->closure_type, 3);
         bc_set_flags(&flags, &idx, cv->is_const, 1);
         bc_set_flags(&flags, &idx, cv->is_lexical, 1);
         bc_set_flags(&flags, &idx, cv->var_kind, 4);
-        assert(idx <= 8);
-        bc_put_u8(s, flags);
+        assert(idx <= 16);
+        bc_put_u16(s, flags);
     }
 
     if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
@@ -37709,14 +38011,13 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
             if (bc_get_leb128_int(s, &var_idx))
                 goto fail;
             cv->var_idx = var_idx;
-            if (bc_get_u8(s, &v8))
+            if (bc_get_u16(s, &v16))
                 goto fail;
             idx = 0;
-            cv->is_local = bc_get_flags(v8, &idx, 1);
-            cv->is_arg = bc_get_flags(v8, &idx, 1);
-            cv->is_const = bc_get_flags(v8, &idx, 1);
-            cv->is_lexical = bc_get_flags(v8, &idx, 1);
-            cv->var_kind = bc_get_flags(v8, &idx, 4);
+            cv->closure_type = bc_get_flags(v16, &idx, 3);
+            cv->is_const = bc_get_flags(v16, &idx, 1);
+            cv->is_lexical = bc_get_flags(v16, &idx, 1);
+            cv->var_kind = bc_get_flags(v16, &idx, 4);
 #ifdef DUMP_READ_OBJECT
             bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); 
printf("\n");
 #endif
@@ -39676,8 +39977,9 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, 
JSValueConst obj,
     if (JS_IsUndefined(species) || JS_IsNull(species))
         return JS_DupValue(ctx, defaultConstructor);
     if (!JS_IsConstructor(ctx, species)) {
+        JS_ThrowTypeErrorNotAConstructor(ctx, species);
         JS_FreeValue(ctx, species);
-        return JS_ThrowTypeError(ctx, "not a constructor");
+        return JS_EXCEPTION;
     }
     return species;
 }
@@ -48520,7 +48822,7 @@ static JSValue js_reflect_construct(JSContext *ctx, 
JSValueConst this_val,
     if (argc > 2) {
         new_target = argv[2];
         if (!JS_IsConstructor(ctx, new_target))
-            return JS_ThrowTypeError(ctx, "not a constructor");
+            return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
     } else {
         new_target = func;
     }
@@ -49439,7 +49741,7 @@ static JSValue js_proxy_call_constructor(JSContext 
*ctx, JSValueConst func_obj,
     if (!s)
         return JS_EXCEPTION;
     if (!JS_IsConstructor(ctx, s->target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
+        return JS_ThrowTypeErrorNotAConstructor(ctx, s->target);
     if (JS_IsUndefined(method))
         return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
     arg_array = js_create_array(ctx, argc, argv);
@@ -49665,7 +49967,7 @@ static JSValue js_symbol_constructor(JSContext *ctx, 
JSValueConst new_target,
     JSString *p;
 
     if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
+        return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
     if (argc == 0 || JS_IsUndefined(argv[0])) {
         p = NULL;
     } else {
@@ -54327,7 +54629,7 @@ static JSValue js_bigint_constructor(JSContext *ctx,
                                      int argc, JSValueConst *argv)
 {
     if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
+        return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
     return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
 }
 
@@ -54493,9 +54795,15 @@ static int JS_AddIntrinsicBasicObjects(JSContext *ctx)
     ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, 
ctx->function_proto);
 
     ctx->global_obj = JS_NewObjectProtoClassAlloc(ctx, 
ctx->class_proto[JS_CLASS_OBJECT],
-                                                  JS_CLASS_OBJECT, 64);
+                                                  JS_CLASS_GLOBAL_OBJECT, 64);
     if (JS_IsException(ctx->global_obj))
         return -1;
+    {
+        JSObject *p;
+        obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL, JS_CLASS_OBJECT, 4);
+        p = JS_VALUE_GET_OBJ(ctx->global_obj);
+        p->u.global_object.uninitialized_vars = obj;
+    }
     ctx->global_var_obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL,
                                                       JS_CLASS_OBJECT, 16);
     if (JS_IsException(ctx->global_var_obj))
@@ -55067,10 +55375,52 @@ static JSValue 
js_array_buffer_get_resizable(JSContext *ctx,
     return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
 }
 
+static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
+{
+    uint32_t size_log2, size_elem;
+    struct list_head *el;
+    JSTypedArray *ta;
+    JSObject *p;
+    uint8_t *data;
+    int64_t len;
+
+    len = abuf->byte_length;
+    data = abuf->data;
+    // update lengths of all typed arrays backed by this array buffer
+    list_for_each(el, &abuf->array_list) {
+        ta = list_entry(el, JSTypedArray, link);
+        p = ta->obj;
+        if (p->class_id == JS_CLASS_DATAVIEW) {
+            if (ta->track_rab) {
+                if (ta->offset < len)
+                    ta->length = len - ta->offset;
+                else
+                    ta->length = 0;
+            }
+        } else {
+            p->u.array.count = 0;
+            p->u.array.u.ptr = NULL;
+            size_log2 = typed_array_size_log2(p->class_id);
+            size_elem = 1 << size_log2;
+            if (ta->track_rab) {
+                if (len >= (int64_t)ta->offset + size_elem) {
+                    p->u.array.count = (len - ta->offset) >> size_log2;
+                    p->u.array.u.ptr = &data[ta->offset];
+                }
+            } else {
+                if (len >= (int64_t)ta->offset + ta->length) {
+                    p->u.array.count = ta->length >> size_log2;
+                    p->u.array.u.ptr = &data[ta->offset];
+                }
+            }
+        }
+    }
+    
+}
+
 void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
 {
     JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
-    struct list_head *el;
 
     if (!abuf || abuf->detached)
         return;
@@ -55079,19 +55429,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst 
obj)
     abuf->data = NULL;
     abuf->byte_length = 0;
     abuf->detached = TRUE;
-
-    list_for_each(el, &abuf->array_list) {
-        JSTypedArray *ta;
-        JSObject *p;
-
-        ta = list_entry(el, JSTypedArray, link);
-        p = ta->obj;
-        /* Note: the typed array length and offset fields are not modified */
-        if (p->class_id != JS_CLASS_DATAVIEW) {
-            p->u.array.count = 0;
-            p->u.array.u.ptr = NULL;
-        }
-    }
+    js_array_buffer_update_typed_arrays(abuf);
 }
 
 /* get an ArrayBuffer or SharedArrayBuffer */
@@ -55206,6 +55544,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
         abuf->data = NULL;
         abuf->byte_length = 0;
         abuf->detached = TRUE;
+        js_array_buffer_update_typed_arrays(abuf);
         return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, 
pmax_len,
                                             JS_CLASS_ARRAY_BUFFER,
                                             bs, free_func,
@@ -55216,11 +55555,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
 static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
                                       int argc, JSValueConst *argv, int 
class_id)
 {
-    uint32_t size_log2, size_elem;
-    struct list_head *el;
     JSArrayBuffer *abuf;
-    JSTypedArray *ta;
-    JSObject *p;
     uint8_t *data;
     int64_t len;
 
@@ -55263,29 +55598,7 @@ static JSValue js_array_buffer_resize(JSContext *ctx, 
JSValueConst this_val,
         abuf->byte_length = len;
         abuf->data = data;
     }
-    data = abuf->data;
-    // update lengths of all typed arrays backed by this array buffer
-    list_for_each(el, &abuf->array_list) {
-        ta = list_entry(el, JSTypedArray, link);
-        p = ta->obj;
-        if (p->class_id == JS_CLASS_DATAVIEW)
-            continue;
-        p->u.array.count = 0;
-        p->u.array.u.ptr = NULL;
-        size_log2 = typed_array_size_log2(p->class_id);
-        size_elem = 1 << size_log2;
-        if (ta->track_rab) {
-            if (len >= (int64_t)ta->offset + size_elem) {
-                p->u.array.count = (len - ta->offset) >> size_log2;
-                p->u.array.u.ptr = &data[ta->offset];
-            }
-        } else {
-            if (len >= (int64_t)ta->offset + ta->length) {
-                p->u.array.count = ta->length >> size_log2;
-                p->u.array.u.ptr = &data[ta->offset];
-            }
-        }
-    }
+    js_array_buffer_update_typed_arrays(abuf);
     return JS_UNDEFINED;
 }
 
@@ -55344,7 +55657,7 @@ static JSValue js_array_buffer_slice(JSContext *ctx,
         goto fail;
     }
     /* must test again because of side effects */
-    if (abuf->detached) {
+    if (abuf->detached || abuf->byte_length < start + new_len) {
         JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
         goto fail;
     }
diff --git a/src/couch_quickjs/quickjs/test262_errors.txt 
b/src/couch_quickjs/quickjs/test262_errors.txt
index 247ae4470..cc49b2f32 100644
--- a/src/couch_quickjs/quickjs/test262_errors.txt
+++ b/src/couch_quickjs/quickjs/test262_errors.txt
@@ -5,6 +5,19 @@ 
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-
 
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js:27:
 SyntaxError: invalid increment/decrement operand
 
test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33:
 SyntaxError: invalid assignment left-hand side
 
test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20:
 SyntaxError: invalid assignment left-hand side
+test262/test/language/expressions/assignment/S11.13.1_A6_T1.js:23: 
Test262Error: #1: innerX === undefined. Actual: 1
+test262/test/language/expressions/assignment/S11.13.1_A6_T2.js:23: 
Test262Error: #1: innerX === 2. Actual: 1
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.1_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 12
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.2_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 5
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.3_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 3
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.4_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 4
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.5_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 4
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.6_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 8
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.7_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 4
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.8_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 4
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.9_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 1
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.10_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 5
+test262/test/language/expressions/compound-assignment/S11.13.2_A6.11_T1.js:24: 
Test262Error: #1: innerX === 2. Actual: 5
 test262/test/language/identifier-resolution/assign-to-global-undefined.js:20: 
strict mode: expected error
 test262/test/language/statements/expression/S12.4_A1.js:15: unexpected error 
type: Test262: This statement should not be evaluated.
 test262/test/language/statements/expression/S12.4_A1.js:15: strict mode: 
unexpected error type: Test262: This statement should not be evaluated.
@@ -37,9 +50,6 @@ test262/test/staging/sm/class/boundFunctionSubclassing.js:9: 
strict mode: Test26
 test262/test/staging/sm/class/strictExecution.js:13: Test262Error: Expected a 
TypeError to be thrown but no exception was thrown at all
 test262/test/staging/sm/class/superPropOrdering.js:17: Test262Error: Expected 
a TypeError to be thrown but no exception was thrown at all
 test262/test/staging/sm/class/superPropOrdering.js:17: strict mode: 
Test262Error: Expected a TypeError to be thrown but no exception was thrown at 
all
-test262/test/staging/sm/expressions/short-circuit-compound-assignment-const.js:96:
 TypeError: 'a' is read-only
-test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:18:
 Test262Error: Expected a ReferenceError but got a TypeError
-test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:18:
 strict mode: Test262Error: Expected a ReferenceError but got a TypeError
 test262/test/staging/sm/generators/syntax.js:50: Test262Error: Expected a 
SyntaxError to be thrown but no exception was thrown at all
 
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:13:
 Test262Error: Expected SameValue(«"object"», «"function"») to be true
 
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js:11:
 Test262Error: Expected SameValue(«"outer-gouter-geval-gtruefalseq"», 
«"outer-geval-gwith-gtruefalseq"») to be true

Reply via email to