Browse Source

Updated tc39 tests. A number of fixes as a result:

- Fixed panic if target ArrayBuffer gets detached during TypedArray.from().
- Use the "flags" property, rather than "global" and "unicode" in RegExp matcher and replacer.
- Do not throw if ArrayBuffer is detached during TypedArray.sort().
- Do not use species constructor when creating a TypedArray from another TypedArray.
- Allow global lexical bindings override variable bindings created by eval().
- Do not accept -00000 as year in Date.parse().
- Fixed object references with Symbol property names.
- Do not call toPropertyKey prematurely when creating object references and some other cases.
- Make "Infinity" case-sensitive and do not accept "inf" in Number().
Dmitry Panov 1 year ago
parent
commit
ac2ea62348
10 changed files with 166 additions and 84 deletions
  1. 2 2
      .tc39_test262_checkout.sh
  2. 10 7
      builtin_regexp.go
  3. 23 11
      builtin_typedarrays.go
  4. 0 12
      compiler_test.go
  5. 4 0
      date_parser.go
  6. 1 2
      runtime.go
  7. 11 0
      runtime_test.go
  8. 8 1
      string_ascii.go
  9. 35 0
      tc39_test.go
  10. 72 49
      vm.go

+ 2 - 2
.tc39_test262_checkout.sh

@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/bin/sh -e
 # this is just the commit it was last tested with
-sha=926b0960d737b9f1dfd0ec0c1dfd95d836016d33
+sha=cb4a6c8074671c00df8cbc17a620c0f9462b312a
 
 mkdir -p testdata/test262
 cd testdata/test262

+ 10 - 7
builtin_regexp.go

@@ -688,8 +688,7 @@ func (r *Runtime) regExpExec(execFn func(FunctionCall) Value, rxObj *Object, arg
 	return res
 }
 
-func (r *Runtime) getGlobalRegexpMatches(rxObj *Object, s String) []Value {
-	fullUnicode := nilSafe(rxObj.self.getStr("unicode", nil)).ToBoolean()
+func (r *Runtime) getGlobalRegexpMatches(rxObj *Object, s String, fullUnicode bool) []Value {
 	rxObj.self.setOwnStr("lastIndex", intToValue(0), true)
 	execFn, ok := r.toObject(rxObj.self.getStr("exec", nil)).self.assertCallable()
 	if !ok {
@@ -714,9 +713,10 @@ func (r *Runtime) getGlobalRegexpMatches(rxObj *Object, s String) []Value {
 
 func (r *Runtime) regexpproto_stdMatcherGeneric(rxObj *Object, s String) Value {
 	rx := rxObj.self
-	global := rx.getStr("global", nil)
-	if global != nil && global.ToBoolean() {
-		a := r.getGlobalRegexpMatches(rxObj, s)
+	flags := nilSafe(rx.getStr("flags", nil)).String()
+	global := strings.ContainsRune(flags, 'g')
+	if global {
+		a := r.getGlobalRegexpMatches(rxObj, s, strings.ContainsRune(flags, 'u'))
 		if len(a) == 0 {
 			return _null
 		}
@@ -1092,8 +1092,11 @@ RETURN:
 
 func (r *Runtime) regexpproto_stdReplacerGeneric(rxObj *Object, s, replaceStr String, rcall func(FunctionCall) Value) Value {
 	var results []Value
-	if nilSafe(rxObj.self.getStr("global", nil)).ToBoolean() {
-		results = r.getGlobalRegexpMatches(rxObj, s)
+	flags := nilSafe(rxObj.self.getStr("flags", nil)).String()
+	isGlobal := strings.ContainsRune(flags, 'g')
+	isUnicode := strings.ContainsRune(flags, 'u')
+	if isGlobal {
+		results = r.getGlobalRegexpMatches(rxObj, s, isUnicode)
 	} else {
 		execFn := toMethod(rxObj.self.getStr("exec", nil)) // must be non-nil
 		result := r.regExpExec(execFn, rxObj, s)

+ 23 - 11
builtin_typedarrays.go

@@ -14,17 +14,25 @@ type typedArraySortCtx struct {
 	ta           *typedArrayObject
 	compare      func(FunctionCall) Value
 	needValidate bool
+	detached     bool
 }
 
 func (ctx *typedArraySortCtx) Len() int {
 	return ctx.ta.length
 }
 
-func (ctx *typedArraySortCtx) Less(i, j int) bool {
-	if ctx.needValidate {
-		ctx.ta.viewedArrayBuf.ensureNotDetached(true)
+func (ctx *typedArraySortCtx) checkDetached() {
+	if !ctx.detached && ctx.needValidate {
+		ctx.detached = !ctx.ta.viewedArrayBuf.ensureNotDetached(false)
 		ctx.needValidate = false
 	}
+}
+
+func (ctx *typedArraySortCtx) Less(i, j int) bool {
+	ctx.checkDetached()
+	if ctx.detached {
+		return false
+	}
 	offset := ctx.ta.offset
 	if ctx.compare != nil {
 		x := ctx.ta.typedArray.get(offset + i)
@@ -54,9 +62,9 @@ func (ctx *typedArraySortCtx) Less(i, j int) bool {
 }
 
 func (ctx *typedArraySortCtx) Swap(i, j int) {
-	if ctx.needValidate {
-		ctx.ta.viewedArrayBuf.ensureNotDetached(true)
-		ctx.needValidate = false
+	ctx.checkDetached()
+	if ctx.detached {
+		return
 	}
 	offset := ctx.ta.offset
 	ctx.ta.typedArray.swap(offset+i, offset+j)
@@ -146,7 +154,6 @@ func (r *Runtime) newDataView(args []Value, newTarget *Object) *Object {
 	if newTarget == nil {
 		panic(r.needNew("DataView"))
 	}
-	proto := r.getPrototypeFromCtor(newTarget, r.getDataView(), r.getDataViewPrototype())
 	var bufArg Value
 	if len(args) > 0 {
 		bufArg = args[0]
@@ -177,6 +184,14 @@ func (r *Runtime) newDataView(args []Value, newTarget *Object) *Object {
 	} else {
 		byteLen = len(buffer.data) - byteOffset
 	}
+	proto := r.getPrototypeFromCtor(newTarget, r.getDataView(), r.getDataViewPrototype())
+	buffer.ensureNotDetached(true)
+	if byteOffset > len(buffer.data) {
+		panic(r.newError(r.getRangeError(), "Start offset %d is outside the bounds of the buffer", byteOffset))
+	}
+	if byteOffset+byteLen > len(buffer.data) {
+		panic(r.newError(r.getRangeError(), "Invalid DataView length %d", byteLen))
+	}
 	o := &Object{runtime: r}
 	b := &dataViewObject{
 		baseObject: baseObject{
@@ -1007,7 +1022,6 @@ func (r *Runtime) typedArrayProto_set(call FunctionCall) Value {
 			}
 			for i := 0; i < srcLen; i++ {
 				val := nilSafe(srcObj.self.getIdx(valueInt(i), nil))
-				ta.viewedArrayBuf.ensureNotDetached(true)
 				if ta.isValidIntegerIndex(i) {
 					ta.typedArray.set(targetOffset+i, val)
 				}
@@ -1270,7 +1284,7 @@ func (r *Runtime) typedArray_from(call FunctionCall) Value {
 			for idx, val := range values {
 				fc.Arguments[0], fc.Arguments[1] = val, intToValue(int64(idx))
 				val = mapFc(fc)
-				ta.typedArray.set(idx, val)
+				ta._putIdx(idx, val)
 			}
 		}
 		return ta.val
@@ -1417,8 +1431,6 @@ func (r *Runtime) _newTypedArrayFromTypedArray(src *typedArrayObject, newTarget
 	src.viewedArrayBuf.ensureNotDetached(true)
 	l := src.length
 
-	arrayBuffer := r.getArrayBuffer()
-	dst.viewedArrayBuf.prototype = r.getPrototypeFromCtor(r.speciesConstructorObj(src.viewedArrayBuf.val, arrayBuffer), arrayBuffer, r.getArrayBufferPrototype())
 	dst.viewedArrayBuf.data = allocByteSlice(toIntStrict(int64(l) * int64(dst.elemSize)))
 	src.viewedArrayBuf.ensureNotDetached(true)
 	if src.defaultCtor == dst.defaultCtor {

+ 0 - 12
compiler_test.go

@@ -3135,18 +3135,6 @@ func TestDeleteGlobalEval(t *testing.T) {
 	testScript(SCRIPT, valueTrue, t)
 }
 
-func TestGlobalVarNames(t *testing.T) {
-	vm := New()
-	_, err := vm.RunString("(0,eval)('var x')")
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = vm.RunString("let x")
-	if err == nil {
-		t.Fatal("Expected error")
-	}
-}
-
 func TestTryResultEmpty(t *testing.T) {
 	const SCRIPT = `
 	1; try { } finally { }

+ 4 - 0
date_parser.go

@@ -123,6 +123,10 @@ func parseDate(layout, value string, defaultLocation *time.Location) (time.Time,
 				p, value = value[1:7], value[7:]
 				year, err = atoi(p)
 				if neg {
+					if year == 0 {
+						err = errBad
+						break
+					}
 					year = -year
 				}
 			} else {

+ 1 - 2
runtime.go

@@ -45,8 +45,7 @@ const (
 )
 
 type global struct {
-	stash    stash
-	varNames map[unistring.String]struct{}
+	stash stash
 
 	Object   *Object
 	Array    *Object

+ 11 - 0
runtime_test.go

@@ -2968,6 +2968,17 @@ func ExampleRuntime_ForOf() {
 	// Output: a=1,b=2,
 }
 
+func TestDestructAssignToSymbol(t *testing.T) {
+	const SCRIPT = `
+	const s = Symbol('s');
+	const target = {};
+
+	({a: target[s]} = {a: 42});
+	assert.sameValue(target[s], 42);
+`
+	testScriptWithTestLib(SCRIPT, _undefined, t)
+}
+
 /*
 func TestArrayConcatSparse(t *testing.T) {
 function foo(a,b,c)

+ 8 - 1
string_ascii.go

@@ -114,7 +114,7 @@ func isRangeErr(err error) bool {
 }
 
 func (s asciiString) _toFloat() (float64, error) {
-	ss := strings.TrimSpace(string(s))
+	ss := strings.ToLower(strings.TrimSpace(string(s)))
 	if ss == "" {
 		return 0, nil
 	}
@@ -122,7 +122,14 @@ func (s asciiString) _toFloat() (float64, error) {
 		var f float64
 		return -f, nil
 	}
+
 	f, err := strconv.ParseFloat(ss, 64)
+	if err == nil && math.IsInf(f, 0) {
+		if strings.HasPrefix(ss, "inf") || strings.HasPrefix(ss, "-inf") || strings.HasPrefix(ss, "+inf") {
+			// We handle "Infinity" separately, prevent from being parsed as Infinity due to strconv.ParseFloat() permissive syntax
+			return 0, strconv.ErrSyntax
+		}
+	}
 	if isRangeErr(err) {
 		err = nil
 	}

+ 35 - 0
tc39_test.go

@@ -185,6 +185,17 @@ var (
 		"test/built-ins/TypedArray/prototype/toReversed/this-value-invalid.js":     true,
 		"test/built-ins/TypedArray/prototype/toSorted/comparefn-not-a-function.js": true,
 		"test/built-ins/TypedArray/prototype/toSorted/this-value-invalid.js":       true,
+		"test/built-ins/RegExp/prototype/sticky/this-val-non-obj.js":               true,
+		"test/built-ins/RegExp/prototype/source/this-val-non-obj.js":               true,
+		"test/built-ins/RegExp/prototype/multiline/this-val-non-obj.js":            true,
+		"test/built-ins/RegExp/prototype/ignoreCase/this-val-non-obj.js":           true,
+		"test/built-ins/RegExp/prototype/unicode/this-val-non-obj.js":              true,
+		"test/built-ins/RegExp/prototype/dotAll/this-val-non-obj.js":               true,
+		"test/built-ins/RegExp/prototype/global/this-val-non-obj.js":               true,
+		"test/built-ins/RegExp/prototype/flags/this-val-non-obj.js":                true,
+		"test/built-ins/Iterator/prototype/Symbol.iterator/return-val.js":          true,
+		"test/built-ins/DataView/prototype/setBigUint64/not-a-constructor.js":      true,
+		"test/built-ins/DataView/prototype/getBigUint64/not-a-constructor.js":      true,
 
 		// Regexp
 		"test/language/literals/regexp/invalid-range-negative-lookbehind.js":    true,
@@ -192,6 +203,9 @@ var (
 		"test/language/literals/regexp/invalid-optional-negative-lookbehind.js": true,
 		"test/language/literals/regexp/invalid-optional-lookbehind.js":          true,
 
+		// unicode full case folding
+		"test/built-ins/RegExp/unicode_full_case_folding.js": true,
+
 		// FIXME bugs
 
 		// Left-hand side as a CoverParenthesizedExpression
@@ -203,6 +217,9 @@ var (
 
 		// Skip due to regexp named groups
 		"test/built-ins/String/prototype/replaceAll/searchValue-replacer-RegExp-call.js": true,
+
+		"test/built-ins/RegExp/nullable-quantifier.js":               true,
+		"test/built-ins/RegExp/lookahead-quantifier-match-groups.js": true,
 	}
 
 	featuresBlackList = []string{
@@ -211,8 +228,11 @@ var (
 		"BigInt",
 		"resizable-arraybuffer",
 		"regexp-named-groups",
+		"regexp-duplicate-named-groups",
 		"regexp-unicode-property-escapes",
 		"regexp-match-indices",
+		"regexp-modifiers",
+		"RegExp.escape",
 		"legacy-regexp",
 		"tail-call-optimization",
 		"Temporal",
@@ -222,6 +242,7 @@ var (
 		"import.meta",
 		"Atomics",
 		"Atomics.waitAsync",
+		"Atomics.pause",
 		"FinalizationRegistry",
 		"WeakRef",
 		"numeric-separator-literal",
@@ -231,6 +252,20 @@ var (
 		"SharedArrayBuffer",
 		"decorators",
 		"regexp-v-flag",
+		"iterator-helpers",
+		"symbols-as-weakmap-keys",
+		"uint8array-base64",
+		"String.prototype.toWellFormed",
+		"explicit-resource-management",
+		"set-methods",
+		"promise-try",
+		"promise-with-resolvers",
+		"array-grouping",
+		"Math.sumPrecise",
+		"Float16Array",
+		"arraybuffer-transfer",
+		"Array.fromAsync",
+		"String.prototype.isWellFormed",
 	}
 )
 

+ 72 - 49
vm.go

@@ -208,6 +208,48 @@ func (r *stashRefConst) set(v Value) {
 }
 
 type objRef struct {
+	base   *Object
+	name   Value
+	this   Value
+	strict bool
+
+	nameConverted bool
+}
+
+func (r *objRef) getKey() Value {
+	if !r.nameConverted {
+		r.name = toPropertyKey(r.name)
+		r.nameConverted = true
+	}
+	return r.name
+}
+
+func (r *objRef) get() Value {
+	return r.base.get(r.getKey(), r.this)
+}
+
+func (r *objRef) set(v Value) {
+	key := r.getKey()
+	if r.this != nil {
+		r.base.set(key, v, r.this, r.strict)
+	} else {
+		r.base.setOwn(key, v, r.strict)
+	}
+}
+
+func (r *objRef) init(v Value) {
+	if r.this != nil {
+		r.base.set(r.getKey(), v, r.this, r.strict)
+	} else {
+		r.base.setOwn(r.getKey(), v, r.strict)
+	}
+}
+
+func (r *objRef) refname() unistring.String {
+	return r.getKey().string()
+}
+
+type objStrRef struct {
 	base    *Object
 	name    unistring.String
 	this    Value
@@ -215,11 +257,11 @@ type objRef struct {
 	binding bool
 }
 
-func (r *objRef) get() Value {
+func (r *objStrRef) get() Value {
 	return r.base.self.getStr(r.name, r.this)
 }
 
-func (r *objRef) set(v Value) {
+func (r *objStrRef) set(v Value) {
 	if r.strict && r.binding && !r.base.self.hasOwnPropertyStr(r.name) {
 		panic(referenceError(fmt.Sprintf("%s is not defined", r.name)))
 	}
@@ -230,7 +272,7 @@ func (r *objRef) set(v Value) {
 	}
 }
 
-func (r *objRef) init(v Value) {
+func (r *objStrRef) init(v Value) {
 	if r.this != nil {
 		r.base.setStr(r.name, v, r.this, r.strict)
 	} else {
@@ -238,7 +280,7 @@ func (r *objRef) init(v Value) {
 	}
 }
 
-func (r *objRef) refname() unistring.String {
+func (r *objStrRef) refname() unistring.String {
 	return r.name
 }
 
@@ -465,7 +507,7 @@ func (s *stash) getByName(name unistring.String) (v Value, exists bool) {
 func (s *stash) getRefByName(name unistring.String, strict bool) ref {
 	if obj := s.obj; obj != nil {
 		if stashObjHas(obj, name) {
-			return &objRef{
+			return &objStrRef{
 				base:    obj,
 				name:    name,
 				strict:  strict,
@@ -1588,10 +1630,10 @@ var getElemRef _getElemRef
 
 func (_getElemRef) exec(vm *vm) {
 	obj := vm.stack[vm.sp-2].ToObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-1])
+	propName := vm.stack[vm.sp-1]
 	vm.refStack = append(vm.refStack, &objRef{
 		base: obj,
-		name: propName.string(),
+		name: propName,
 	})
 	vm.sp -= 2
 	vm.pc++
@@ -1603,10 +1645,10 @@ var getElemRefRecv _getElemRefRecv
 
 func (_getElemRefRecv) exec(vm *vm) {
 	obj := vm.stack[vm.sp-1].ToObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-2])
+	propName := vm.stack[vm.sp-2]
 	vm.refStack = append(vm.refStack, &objRef{
 		base: obj,
-		name: propName.string(),
+		name: propName,
 		this: vm.stack[vm.sp-3],
 	})
 	vm.sp -= 3
@@ -1619,10 +1661,10 @@ var getElemRefStrict _getElemRefStrict
 
 func (_getElemRefStrict) exec(vm *vm) {
 	obj := vm.stack[vm.sp-2].ToObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-1])
+	propName := vm.stack[vm.sp-1]
 	vm.refStack = append(vm.refStack, &objRef{
 		base:   obj,
-		name:   propName.string(),
+		name:   propName,
 		strict: true,
 	})
 	vm.sp -= 2
@@ -1635,10 +1677,10 @@ var getElemRefRecvStrict _getElemRefRecvStrict
 
 func (_getElemRefRecvStrict) exec(vm *vm) {
 	obj := vm.stack[vm.sp-1].ToObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-2])
+	propName := vm.stack[vm.sp-2]
 	vm.refStack = append(vm.refStack, &objRef{
 		base:   obj,
-		name:   propName.string(),
+		name:   propName,
 		this:   vm.stack[vm.sp-3],
 		strict: true,
 	})
@@ -1908,7 +1950,7 @@ func (d deletePropStrict) exec(vm *vm) {
 type getPropRef unistring.String
 
 func (p getPropRef) exec(vm *vm) {
-	vm.refStack = append(vm.refStack, &objRef{
+	vm.refStack = append(vm.refStack, &objStrRef{
 		base: vm.stack[vm.sp-1].ToObject(vm.r),
 		name: unistring.String(p),
 	})
@@ -1919,7 +1961,7 @@ func (p getPropRef) exec(vm *vm) {
 type getPropRefRecv unistring.String
 
 func (p getPropRefRecv) exec(vm *vm) {
-	vm.refStack = append(vm.refStack, &objRef{
+	vm.refStack = append(vm.refStack, &objStrRef{
 		this: vm.stack[vm.sp-2],
 		base: vm.stack[vm.sp-1].ToObject(vm.r),
 		name: unistring.String(p),
@@ -1931,7 +1973,7 @@ func (p getPropRefRecv) exec(vm *vm) {
 type getPropRefStrict unistring.String
 
 func (p getPropRefStrict) exec(vm *vm) {
-	vm.refStack = append(vm.refStack, &objRef{
+	vm.refStack = append(vm.refStack, &objStrRef{
 		base:   vm.stack[vm.sp-1].ToObject(vm.r),
 		name:   unistring.String(p),
 		strict: true,
@@ -1943,7 +1985,7 @@ func (p getPropRefStrict) exec(vm *vm) {
 type getPropRefRecvStrict unistring.String
 
 func (p getPropRefRecvStrict) exec(vm *vm) {
-	vm.refStack = append(vm.refStack, &objRef{
+	vm.refStack = append(vm.refStack, &objStrRef{
 		this:   vm.stack[vm.sp-2],
 		base:   vm.stack[vm.sp-1].ToObject(vm.r),
 		name:   unistring.String(p),
@@ -2330,11 +2372,11 @@ var getElem _getElem
 func (_getElem) exec(vm *vm) {
 	v := vm.stack[vm.sp-2]
 	obj := v.baseObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if obj == nil {
-		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
+		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", vm.stack[vm.sp-1]))
 		return
 	}
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 
 	vm.stack[vm.sp-2] = nilSafe(obj.get(propName, v))
 
@@ -2348,13 +2390,13 @@ var getElemRecv _getElemRecv
 
 func (_getElemRecv) exec(vm *vm) {
 	recv := vm.stack[vm.sp-3]
-	propName := toPropertyKey(vm.stack[vm.sp-2])
 	v := vm.stack[vm.sp-1]
 	obj := v.baseObject(vm.r)
 	if obj == nil {
-		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
+		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", vm.stack[vm.sp-2]))
 		return
 	}
+	propName := toPropertyKey(vm.stack[vm.sp-2])
 
 	vm.stack[vm.sp-3] = nilSafe(obj.get(propName, recv))
 
@@ -2388,12 +2430,12 @@ var getElemCallee _getElemCallee
 func (_getElemCallee) exec(vm *vm) {
 	v := vm.stack[vm.sp-2]
 	obj := v.baseObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if obj == nil {
-		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
+		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", vm.stack[vm.sp-1]))
 		return
 	}
 
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	prop := obj.get(propName, v)
 	if prop == nil {
 		prop = memberUnresolved{valueUnresolved{r: vm.r, ref: propName.string()}}
@@ -2411,12 +2453,12 @@ func (_getElemRecvCallee) exec(vm *vm) {
 	recv := vm.stack[vm.sp-3]
 	v := vm.stack[vm.sp-2]
 	obj := v.baseObject(vm.r)
-	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if obj == nil {
-		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
+		vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", vm.stack[vm.sp-1]))
 		return
 	}
 
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	prop := obj.get(propName, recv)
 	if prop == nil {
 		prop = memberUnresolved{valueUnresolved{r: vm.r, ref: propName.string()}}
@@ -2654,7 +2696,7 @@ func (s resolveVar1) exec(vm *vm) {
 		}
 	}
 
-	ref = &objRef{
+	ref = &objStrRef{
 		base:    vm.r.globalObject,
 		name:    name,
 		binding: true,
@@ -2708,9 +2750,6 @@ func (d deleteGlobal) exec(vm *vm) {
 	var ret bool
 	if vm.r.globalObject.self.hasPropertyStr(name) {
 		ret = vm.r.globalObject.self.deleteStr(name, false)
-		if ret {
-			delete(vm.r.global.varNames, name)
-		}
 	} else {
 		ret = true
 	}
@@ -2735,7 +2774,7 @@ func (s resolveVar1Strict) exec(vm *vm) {
 	}
 
 	if vm.r.globalObject.self.hasPropertyStr(name) {
-		ref = &objRef{
+		ref = &objStrRef{
 			base:    vm.r.globalObject,
 			name:    name,
 			binding: true,
@@ -3876,18 +3915,12 @@ func (vm *vm) checkBindVarsGlobal(names []unistring.String) {
 }
 
 func (vm *vm) createGlobalVarBindings(names []unistring.String, d bool) {
-	globalVarNames := vm.r.global.varNames
-	if globalVarNames == nil {
-		globalVarNames = make(map[unistring.String]struct{})
-		vm.r.global.varNames = globalVarNames
-	}
 	o := vm.r.globalObject.self
-	if bo, ok := o.(*baseObject); ok {
+	if bo, ok := o.(*templatedObject); ok {
 		for _, name := range names {
 			if !bo.hasOwnPropertyStr(name) && bo.extensible {
 				bo._putProp(name, _undefined, true, true, d)
 			}
-			globalVarNames[name] = struct{}{}
 		}
 	} else {
 		var cf Flag
@@ -3906,21 +3939,15 @@ func (vm *vm) createGlobalVarBindings(names []unistring.String, d bool) {
 				}, true)
 				o.setOwnStr(name, _undefined, false)
 			}
-			globalVarNames[name] = struct{}{}
 		}
 	}
 }
 
 func (vm *vm) createGlobalFuncBindings(names []unistring.String, d bool) {
-	globalVarNames := vm.r.global.varNames
-	if globalVarNames == nil {
-		globalVarNames = make(map[unistring.String]struct{})
-		vm.r.global.varNames = globalVarNames
-	}
 	o := vm.r.globalObject.self
 	b := vm.sp - len(names)
-	var shortcutObj *baseObject
-	if o, ok := o.(*baseObject); ok {
+	var shortcutObj *templatedObject
+	if o, ok := o.(*templatedObject); ok {
 		shortcutObj = o
 	}
 	for i, name := range names {
@@ -3948,7 +3975,6 @@ func (vm *vm) createGlobalFuncBindings(names []unistring.String, d bool) {
 				o.setOwnStr(name, desc.Value, false) // not a bug, see https://262.ecma-international.org/#sec-createglobalfunctionbinding
 			}
 		}
-		globalVarNames[name] = struct{}{}
 	}
 	vm.sp = b
 }
@@ -3978,9 +4004,6 @@ func (vm *vm) checkBindLexGlobal(names []unistring.String) {
 	o := vm.r.globalObject.self
 	s := &vm.r.global.stash
 	for _, name := range names {
-		if _, exists := vm.r.global.varNames[name]; exists {
-			goto fail
-		}
 		if _, exists := s.names[name]; exists {
 			goto fail
 		}