Browse Source

Merge branch 'master' into es6

# Conflicts:
#	vm.go
Dmitry Panov 5 years ago
parent
commit
cb8f52dd97
3 changed files with 95 additions and 12 deletions
  1. 19 2
      compiler_expr.go
  2. 28 0
      compiler_test.go
  3. 48 10
      vm.go

+ 19 - 2
compiler_expr.go

@@ -316,6 +316,24 @@ func (e *compiledIdentifierExpr) emitGetterOrRef() {
 	} else {
 		if found {
 			e.c.emit(getVar{name: e.name, idx: idx, ref: true})
+		} else {
+			e.c.emit(getVar1Ref(e.name))
+		}
+	}
+}
+
+func (e *compiledIdentifierExpr) emitGetterAndCallee() {
+	e.addSrcMap()
+	if idx, found, noDynamics := e.c.scope.lookupName(e.name); noDynamics {
+		if found {
+			e.c.emit(loadUndef)
+			e.c.emit(getLocal(idx))
+		} else {
+			panic("No dynamics and not found")
+		}
+	} else {
+		if found {
+			e.c.emit(getVar{name: e.name, idx: idx, ref: true, callee: true})
 		} else {
 			e.c.emit(getVar1Callee(e.name))
 		}
@@ -1458,9 +1476,8 @@ func (e *compiledCallExpr) emitGetter(putOnStack bool) {
 		callee.member.emitGetter(true)
 		e.c.emit(getElemCallee)
 	case *compiledIdentifierExpr:
-		e.c.emit(loadUndef)
 		calleeName = callee.name
-		callee.emitGetterOrRef()
+		callee.emitGetterAndCallee()
 	default:
 		e.c.emit(loadUndef)
 		callee.emitGetter(true)

+ 28 - 0
compiler_test.go

@@ -2053,6 +2053,34 @@ func TestIfStackLeaks(t *testing.T) {
 	testScript1(SCRIPT, _positiveZero, t)
 }
 
+func TestWithCallee(t *testing.T) {
+	const SCRIPT = `
+	function O() {
+		var that = this;
+		this.m = function() {
+			return this === that;
+		}
+	}
+	with(new O()) {
+		m();
+	}
+	`
+	testScript1(SCRIPT, valueTrue, t)
+}
+
+func TestEvalCallee(t *testing.T) {
+	const SCRIPT = `
+	(function () {
+		'use strict';
+		var v = function() {
+			return this === undefined;
+		};
+		return eval('v()');
+	})();
+	`
+	testScript1(SCRIPT, valueTrue, t)
+}
+
 // FIXME
 /*
 func TestDummyCompile(t *testing.T) {

+ 48 - 10
vm.go

@@ -21,7 +21,7 @@ type stash struct {
 	values    valueStack
 	extraArgs valueStack
 	names     map[unistring.String]uint32
-	obj       objectImpl
+	obj       *Object
 
 	outer *stash
 }
@@ -218,7 +218,7 @@ func stashObjHas(obj objectImpl, name unistring.String) bool {
 func (s *stash) put(name unistring.String, v Value) bool {
 	if s.obj != nil {
 		if stashObjHas(s.obj, name) {
-			s.obj.setOwnStr(name, v, false)
+			s.obj.self.setOwnStr(name, v, false)
 			return true
 		}
 		return false
@@ -250,7 +250,7 @@ func (s *stash) getByIdx(idx uint32) Value {
 func (s *stash) getByName(name unistring.String, _ *vm) (v Value, exists bool) {
 	if s.obj != nil {
 		if stashObjHas(s.obj, name) {
-			return nilSafe(s.obj.getStr(name, nil)), true
+			return nilSafe(s.obj.self.getStr(name, nil)), true
 		}
 		return nil, false
 	}
@@ -274,7 +274,7 @@ func (s *stash) createBinding(name unistring.String) {
 func (s *stash) deleteBinding(name unistring.String) bool {
 	if s.obj != nil {
 		if stashObjHas(s.obj, name) {
-			return s.obj.deleteStr(name, false)
+			return s.obj.self.deleteStr(name, false)
 		}
 		return false
 	}
@@ -1346,7 +1346,7 @@ func (s resolveVar1) exec(vm *vm) {
 		if stash.obj != nil {
 			if stashObjHas(stash.obj, name) {
 				ref = &objRef{
-					base: stash.obj,
+					base: stash.obj.self,
 					name: name,
 				}
 				goto end
@@ -1379,7 +1379,7 @@ func (d deleteVar) exec(vm *vm) {
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 		if stash.obj != nil {
 			if stashObjHas(stash.obj, name) {
-				ret = stash.obj.deleteStr(name, false)
+				ret = stash.obj.self.deleteStr(name, false)
 				goto end
 			}
 		} else {
@@ -1430,7 +1430,7 @@ func (s resolveVar1Strict) exec(vm *vm) {
 		if stash.obj != nil {
 			if stashObjHas(stash.obj, name) {
 				ref = &objRef{
-					base:   stash.obj,
+					base:   stash.obj.self,
 					name:   name,
 					strict: true,
 				}
@@ -1506,7 +1506,7 @@ func (g getLocal) exec(vm *vm) {
 type getVar struct {
 	name unistring.String
 	idx  uint32
-	ref  bool
+	ref, callee  bool
 }
 
 func (g getVar) exec(vm *vm) {
@@ -1516,11 +1516,21 @@ func (g getVar) exec(vm *vm) {
 	name := g.name
 	for i := 0; i < level; i++ {
 		if v, found := stash.getByName(name, vm); found {
+			if g.callee {
+				if stash.obj != nil {
+					vm.push(stash.obj)
+				} else {
+					vm.push(_undefined)
+				}
+			}
 			vm.push(v)
 			goto end
 		}
 		stash = stash.outer
 	}
+	if g.callee {
+		vm.push(_undefined)
+	}
 	if stash != nil {
 		vm.push(stash.getByIdx(idx))
 	} else {
@@ -1553,7 +1563,7 @@ func (r resolveVar) exec(vm *vm) {
 		if obj := stash.obj; obj != nil {
 			if stashObjHas(obj, r.name) {
 				ref = &objRef{
-					base:   stash.obj,
+					base:   stash.obj.self,
 					name:   r.name,
 					strict: r.strict,
 				}
@@ -1644,13 +1654,36 @@ func (n getVar1) exec(vm *vm) {
 	vm.pc++
 }
 
+type getVar1Ref string
+
+func (n getVar1Ref) exec(vm *vm) {
+	name := string(n)
+	var val Value
+	for stash := vm.stash; stash != nil; stash = stash.outer {
+		if v, exists := stash.getByName(name, vm); exists {
+			val = v
+			break
+		}
+	}
+	if val == nil {
+		val = vm.r.globalObject.self.getStr(name)
+		if val == nil {
+			val = valueUnresolved{r: vm.r, ref: name}
+		}
+	}
+	vm.push(val)
+	vm.pc++
+}
+
 type getVar1Callee unistring.String
 
 func (n getVar1Callee) exec(vm *vm) {
 	name := unistring.String(n)
 	var val Value
+	var callee *Object
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 		if v, exists := stash.getByName(name, vm); exists {
+			callee = stash.obj
 			val = v
 			break
 		}
@@ -1661,6 +1694,11 @@ func (n getVar1Callee) exec(vm *vm) {
 			val = valueUnresolved{r: vm.r, ref: name}
 		}
 	}
+	if callee != nil {
+		vm.push(callee)
+	} else {
+		vm.push(_undefined)
+	}
 	vm.push(val)
 	vm.pc++
 }
@@ -2398,7 +2436,7 @@ var enterWith _enterWith
 
 func (_enterWith) exec(vm *vm) {
 	vm.newStash()
-	vm.stash.obj = vm.stack[vm.sp-1].ToObject(vm.r).self
+	vm.stash.obj = vm.stack[vm.sp-1].ToObject(vm.r)
 	vm.sp--
 	vm.pc++
 }