Skip to content

Commit

Permalink
Set correct 'this' when calling member functions within a 'with' block.
Browse files Browse the repository at this point in the history
Fixes dop251#151.
  • Loading branch information
dop251 committed May 23, 2020
1 parent 77e84ff commit e92122c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 20 deletions.
21 changes: 19 additions & 2 deletions compiler_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,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))
}
Expand Down Expand Up @@ -1423,9 +1441,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)
Expand Down
28 changes: 28 additions & 0 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,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) {
Expand Down
74 changes: 56 additions & 18 deletions vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type stash struct {
values valueStack
extraArgs valueStack
names map[string]uint32
obj objectImpl
obj *Object

outer *stash
}
Expand Down Expand Up @@ -200,8 +200,8 @@ func (s *valueStack) expand(idx int) {

func (s *stash) put(name string, v Value) bool {
if s.obj != nil {
if found := s.obj.getStr(name); found != nil {
s.obj.putStr(name, v, false)
if found := s.obj.self.getStr(name); found != nil {
s.obj.self.putStr(name, v, false)
return true
}
return false
Expand Down Expand Up @@ -232,7 +232,7 @@ func (s *stash) getByIdx(idx uint32) Value {

func (s *stash) getByName(name string, _ *vm) (v Value, exists bool) {
if s.obj != nil {
v = s.obj.getStr(name)
v = s.obj.self.getStr(name)
if v == nil {
return nil, false
//return valueUnresolved{r: vm.r, ref: name}, false
Expand All @@ -258,7 +258,7 @@ func (s *stash) createBinding(name string) {

func (s *stash) deleteBinding(name string) bool {
if s.obj != nil {
return s.obj.deleteStr(name, false)
return s.obj.self.deleteStr(name, false)
}
if idx, found := s.names[name]; found {
s.values[idx] = nil
Expand Down Expand Up @@ -1332,9 +1332,9 @@ func (s resolveVar1) exec(vm *vm) {
var ref ref
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj != nil {
if stash.obj.hasPropertyStr(name) {
if stash.obj.self.hasPropertyStr(name) {
ref = &objRef{
base: stash.obj,
base: stash.obj.self,
name: name,
}
goto end
Expand Down Expand Up @@ -1366,8 +1366,8 @@ func (d deleteVar) exec(vm *vm) {
ret := true
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj != nil {
if stash.obj.hasPropertyStr(name) {
ret = stash.obj.deleteStr(name, false)
if stash.obj.self.hasPropertyStr(name) {
ret = stash.obj.self.deleteStr(name, false)
goto end
}
} else {
Expand Down Expand Up @@ -1416,9 +1416,9 @@ func (s resolveVar1Strict) exec(vm *vm) {
var ref ref
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj != nil {
if stash.obj.hasPropertyStr(name) {
if stash.obj.self.hasPropertyStr(name) {
ref = &objRef{
base: stash.obj,
base: stash.obj.self,
name: name,
strict: true,
}
Expand Down Expand Up @@ -1492,23 +1492,33 @@ func (g getLocal) exec(vm *vm) {
}

type getVar struct {
name string
idx uint32
ref bool
name string
idx uint32
ref, callee bool
}

func (g getVar) exec(vm *vm) {
level := int(g.idx >> 24)
idx := uint32(g.idx & 0x00FFFFFF)
idx := g.idx & 0x00FFFFFF
stash := vm.stash
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 {
Expand Down Expand Up @@ -1539,9 +1549,9 @@ func (r resolveVar) exec(vm *vm) {
var ref ref
for i := 0; i < level; i++ {
if stash.obj != nil {
if stash.obj.hasPropertyStr(r.name) {
if stash.obj.self.hasPropertyStr(r.name) {
ref = &objRef{
base: stash.obj,
base: stash.obj.self,
name: r.name,
strict: r.strict,
}
Expand Down Expand Up @@ -1632,13 +1642,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 string

func (n getVar1Callee) exec(vm *vm) {
name := 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
}
Expand All @@ -1649,6 +1682,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++
}
Expand Down Expand Up @@ -2376,7 +2414,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++
}
Expand Down

0 comments on commit e92122c

Please sign in to comment.