Browse Source

Missing Object methods, ToPropertyKey, GetV

Dmitry Panov 5 years ago
parent
commit
a0559b5ea4
25 changed files with 359 additions and 132 deletions
  1. 1 1
      array.go
  2. 1 1
      array_sparse.go
  3. 3 3
      builtin_function.go
  4. 8 8
      builtin_global.go
  5. 1 1
      builtin_json.go
  6. 1 1
      builtin_map.go
  7. 64 4
      builtin_object.go
  8. 15 15
      builtin_regexp.go
  9. 1 1
      builtin_set.go
  10. 23 23
      builtin_string.go
  11. 2 2
      builtin_symbol.go
  12. 1 1
      builtin_weakmap.go
  13. 1 1
      builtin_weakset.go
  14. 33 14
      object.go
  15. 1 1
      object_goreflect.go
  16. 6 0
      object_lazy.go
  17. 1 1
      object_test.go
  18. 29 7
      runtime.go
  19. 70 0
      runtime_test.go
  20. 5 1
      string_ascii.go
  21. 5 1
      string_unicode.go
  22. 12 7
      tc39_test.go
  23. 62 24
      value.go
  24. 11 12
      vm.go
  25. 2 2
      vm_test.go

+ 1 - 1
array.go

@@ -485,7 +485,7 @@ func (a *arrayObject) _deleteProp(idx int64, throw bool) bool {
 		if v := a.values[idx]; v != nil {
 			if p, ok := v.(*valueProperty); ok {
 				if !p.configurable {
-					a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.ToString())
+					a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
 					return false
 				}
 				a.propValueCount--

+ 1 - 1
array_sparse.go

@@ -384,7 +384,7 @@ func (a *sparseArrayObject) _deleteProp(idx int64, throw bool) bool {
 	if i < len(a.items) && a.items[i].idx == idx {
 		if p, ok := a.items[i].value.(*valueProperty); ok {
 			if !p.configurable {
-				a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.ToString())
+				a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
 				return false
 			}
 			a.propValueCount--

+ 3 - 3
builtin_function.go

@@ -28,9 +28,9 @@ repeat:
 	case *funcObject:
 		return newStringValue(f.src)
 	case *nativeFuncObject:
-		return newStringValue(fmt.Sprintf("function %s() { [native code] }", f.nameProp.get(call.This).ToString()))
+		return newStringValue(fmt.Sprintf("function %s() { [native code] }", f.nameProp.get(call.This).toString()))
 	case *boundFuncObject:
-		return newStringValue(fmt.Sprintf("function %s() { [native code] }", f.nameProp.get(call.This).ToString()))
+		return newStringValue(fmt.Sprintf("function %s() { [native code] }", f.nameProp.get(call.This).toString()))
 	case *lazyObject:
 		obj.self = f.create(obj)
 		goto repeat
@@ -129,7 +129,7 @@ repeat:
 		f = ff.create(obj)
 		goto repeat
 	default:
-		r.typeErrorResult(true, "Value is not callable: %s", obj.ToString())
+		r.typeErrorResult(true, "Value is not callable: %s", obj.toString())
 	}
 
 	l := int(toUInt32(obj.self.getStr("length")))

+ 8 - 8
builtin_global.go

@@ -26,14 +26,14 @@ func (r *Runtime) builtin_isNaN(call FunctionCall) Value {
 }
 
 func (r *Runtime) builtin_parseInt(call FunctionCall) Value {
-	str := call.Argument(0).ToString().toTrimmedUTF8()
+	str := call.Argument(0).toString().toTrimmedUTF8()
 	radix := int(toInt32(call.Argument(1)))
 	v, _ := parseInt(str, radix)
 	return v
 }
 
 func (r *Runtime) builtin_parseFloat(call FunctionCall) Value {
-	m := parseFloatRegexp.FindStringSubmatch(call.Argument(0).ToString().toTrimmedUTF8())
+	m := parseFloatRegexp.FindStringSubmatch(call.Argument(0).toString().toTrimmedUTF8())
 	if len(m) == 2 {
 		if s := m[1]; s != "" && s != "+" && s != "-" {
 			switch s {
@@ -217,27 +217,27 @@ func unhex(c byte) byte {
 }
 
 func (r *Runtime) builtin_decodeURI(call FunctionCall) Value {
-	uriString := call.Argument(0).ToString()
+	uriString := call.Argument(0).toString()
 	return r._decode(uriString, &uriReservedHash)
 }
 
 func (r *Runtime) builtin_decodeURIComponent(call FunctionCall) Value {
-	uriString := call.Argument(0).ToString()
+	uriString := call.Argument(0).toString()
 	return r._decode(uriString, &emptyEscapeSet)
 }
 
 func (r *Runtime) builtin_encodeURI(call FunctionCall) Value {
-	uriString := call.Argument(0).ToString()
+	uriString := call.Argument(0).toString()
 	return r._encode(uriString, &uriReservedUnescapedHash)
 }
 
 func (r *Runtime) builtin_encodeURIComponent(call FunctionCall) Value {
-	uriString := call.Argument(0).ToString()
+	uriString := call.Argument(0).toString()
 	return r._encode(uriString, &uriUnescaped)
 }
 
 func (r *Runtime) builtin_escape(call FunctionCall) Value {
-	s := call.Argument(0).ToString()
+	s := call.Argument(0).toString()
 	var sb strings.Builder
 	l := s.length()
 	for i := int64(0); i < l; i++ {
@@ -261,7 +261,7 @@ func (r *Runtime) builtin_escape(call FunctionCall) Value {
 }
 
 func (r *Runtime) builtin_unescape(call FunctionCall) Value {
-	s := call.Argument(0).ToString()
+	s := call.Argument(0).toString()
 	l := s.length()
 	_, unicode := s.(unicodeString)
 	var asciiBuf []byte

+ 1 - 1
builtin_json.go

@@ -449,7 +449,7 @@ func (ctx *_builtinJSON_stringifyContext) jo(object *Object) {
 		if !empty {
 			ctx.buf.WriteString(separator)
 		}
-		ctx.quote(name.ToString())
+		ctx.quote(name.toString())
 		if ctx.gap != "" {
 			ctx.buf.WriteString(": ")
 		} else {

+ 1 - 1
builtin_map.go

@@ -151,7 +151,7 @@ func (r *Runtime) builtin_newMap(args []Value) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := mo.getStr("set")
-			iter := r.getIterator(arg.ToObject(r), nil)
+			iter := r.getIterator(arg, nil)
 			i0 := intToValue(0)
 			i1 := intToValue(1)
 			if adder == r.global.mapAdder {

+ 64 - 4
builtin_object.go

@@ -25,7 +25,7 @@ func (r *Runtime) object_getPrototypeOf(call FunctionCall) Value {
 
 func (r *Runtime) object_getOwnPropertyDescriptor(call FunctionCall) Value {
 	obj := call.Argument(0).ToObject(r)
-	propName := call.Argument(1)
+	propName := toPropertyKey(call.Argument(1))
 	desc := obj.self.getOwnProp(propName)
 	if desc == nil {
 		return _undefined
@@ -370,7 +370,7 @@ func (r *Runtime) object_keys(call FunctionCall) Value {
 }
 
 func (r *Runtime) objectproto_hasOwnProperty(call FunctionCall) Value {
-	p := call.Argument(0)
+	p := toPropertyKey(call.Argument(0))
 	o := call.This.ToObject(r)
 	if o.self.hasOwnProperty(p) {
 		return valueTrue
@@ -396,7 +396,7 @@ func (r *Runtime) objectproto_isPrototypeOf(call FunctionCall) Value {
 }
 
 func (r *Runtime) objectproto_propertyIsEnumerable(call FunctionCall) Value {
-	p := call.Argument(0)
+	p := toPropertyKey(call.Argument(0))
 	o := call.This.ToObject(r)
 	pv := o.self.getOwnProp(p)
 	if pv == nil {
@@ -432,13 +432,70 @@ func (r *Runtime) objectproto_toString(call FunctionCall) Value {
 }
 
 func (r *Runtime) objectproto_toLocaleString(call FunctionCall) Value {
-	return call.This.ToObject(r).ToString()
+	toString := toMethod(r.getVStr(call.This, "toString"))
+	return toString(FunctionCall{This: call.This})
 }
 
 func (r *Runtime) objectproto_valueOf(call FunctionCall) Value {
 	return call.This.ToObject(r)
 }
 
+func (r *Runtime) object_assign(call FunctionCall) Value {
+	to := call.Argument(0).ToObject(r)
+	if len(call.Arguments) > 1 {
+		for _, arg := range call.Arguments[1:] {
+			if arg != _undefined && arg != _null {
+				source := arg.ToObject(r)
+				for item, f := source.self.enumerate(false, false)(); f != nil; item, f = f() {
+					p := source.self.getOwnPropStr(item.name)
+					if v, ok := p.(*valueProperty); ok {
+						p = v.get(source)
+					}
+					to.self.putStr(item.name, p, true)
+				}
+
+				for _, sym := range source.self.getOwnSymbols() {
+					p := source.self.getOwnProp(sym)
+					if v, ok := p.(*valueProperty); ok {
+						if !v.enumerable {
+							continue
+						}
+						p = v.get(source)
+					}
+					to.self.put(sym, p, true)
+				}
+			}
+		}
+	}
+
+	return to
+}
+
+func (r *Runtime) object_is(call FunctionCall) Value {
+	return r.toBoolean(call.Argument(0).SameAs(call.Argument(1)))
+}
+
+func (r *Runtime) object_setPrototypeOf(call FunctionCall) Value {
+	o := call.Argument(0)
+	r.checkObjectCoercible(o)
+	proto := call.Argument(1)
+	var protoObj *Object
+	if proto != _null {
+		if obj, ok := proto.(*Object); ok {
+			protoObj = obj
+		} else {
+			panic(r.NewTypeError("Object prototype may only be an Object or null: %s", proto))
+		}
+	}
+	if o, ok := o.(*Object); ok {
+		if res := o.self.setProto(protoObj); res != nil {
+			panic(res)
+		}
+	}
+
+	return o
+}
+
 func (r *Runtime) initObject() {
 	o := r.global.ObjectPrototype.self
 	o._putProp("toString", r.newNativeFunc(r.objectproto_toString, nil, "toString", nil, 0), true, false, true)
@@ -450,10 +507,12 @@ func (r *Runtime) initObject() {
 
 	r.global.Object = r.newNativeFuncConstruct(r.builtin_Object, classObject, r.global.ObjectPrototype, 1)
 	o = r.global.Object.self
+	o._putProp("assign", r.newNativeFunc(r.object_assign, nil, "assign", nil, 2), true, false, true)
 	o._putProp("defineProperty", r.newNativeFunc(r.object_defineProperty, nil, "defineProperty", nil, 3), true, false, true)
 	o._putProp("defineProperties", r.newNativeFunc(r.object_defineProperties, nil, "defineProperties", nil, 2), true, false, true)
 	o._putProp("getOwnPropertyDescriptor", r.newNativeFunc(r.object_getOwnPropertyDescriptor, nil, "getOwnPropertyDescriptor", nil, 2), true, false, true)
 	o._putProp("getPrototypeOf", r.newNativeFunc(r.object_getPrototypeOf, nil, "getPrototypeOf", nil, 1), true, false, true)
+	o._putProp("is", r.newNativeFunc(r.object_is, nil, "is", nil, 2), true, false, true)
 	o._putProp("getOwnPropertyNames", r.newNativeFunc(r.object_getOwnPropertyNames, nil, "getOwnPropertyNames", nil, 1), true, false, true)
 	o._putProp("getOwnPropertySymbols", r.newNativeFunc(r.object_getOwnPropertySymbols, nil, "getOwnPropertySymbols", nil, 1), true, false, true)
 	o._putProp("create", r.newNativeFunc(r.object_create, nil, "create", nil, 2), true, false, true)
@@ -464,6 +523,7 @@ func (r *Runtime) initObject() {
 	o._putProp("isFrozen", r.newNativeFunc(r.object_isFrozen, nil, "isFrozen", nil, 1), true, false, true)
 	o._putProp("isExtensible", r.newNativeFunc(r.object_isExtensible, nil, "isExtensible", nil, 1), true, false, true)
 	o._putProp("keys", r.newNativeFunc(r.object_keys, nil, "keys", nil, 1), true, false, true)
+	o._putProp("setPrototypeOf", r.newNativeFunc(r.object_setPrototypeOf, nil, "setPrototypeOf", nil, 2), true, false, true)
 
 	r.addToGlobal("Object", r.global.Object)
 }

+ 15 - 15
builtin_regexp.go

@@ -133,7 +133,7 @@ func (r *Runtime) builtin_newRegExp(args []Value) *Object {
 			}
 		}
 		if args[0] != _undefined {
-			pattern = args[0].ToString()
+			pattern = args[0].toString()
 		}
 	}
 	if len(args) > 1 {
@@ -161,22 +161,22 @@ func (r *Runtime) builtin_RegExp(call FunctionCall) Value {
 
 func (r *Runtime) regexpproto_exec(call FunctionCall) Value {
 	if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
-		return this.exec(call.Argument(0).ToString())
+		return this.exec(call.Argument(0).toString())
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.exec called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.exec called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
 
 func (r *Runtime) regexpproto_test(call FunctionCall) Value {
 	if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
-		if this.test(call.Argument(0).ToString()) {
+		if this.test(call.Argument(0).toString()) {
 			return valueTrue
 		} else {
 			return valueFalse
 		}
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.test called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.test called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -207,7 +207,7 @@ func (r *Runtime) regexpproto_getSource(call FunctionCall) Value {
 	if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
 		return this.source
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.source getter called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.source getter called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -220,7 +220,7 @@ func (r *Runtime) regexpproto_getGlobal(call FunctionCall) Value {
 			return valueFalse
 		}
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.global getter called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.global getter called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -233,7 +233,7 @@ func (r *Runtime) regexpproto_getMultiline(call FunctionCall) Value {
 			return valueFalse
 		}
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.multiline getter called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.multiline getter called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -246,7 +246,7 @@ func (r *Runtime) regexpproto_getIgnoreCase(call FunctionCall) Value {
 			return valueFalse
 		}
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.ignoreCase getter called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.ignoreCase getter called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -259,7 +259,7 @@ func (r *Runtime) regexpproto_getSticky(call FunctionCall) Value {
 			return valueFalse
 		}
 	} else {
-		r.typeErrorResult(true, "Method RegExp.prototype.sticky getter called on incompatible receiver %s", call.This.ToString())
+		r.typeErrorResult(true, "Method RegExp.prototype.sticky getter called on incompatible receiver %s", call.This.toString())
 		return nil
 	}
 }
@@ -332,7 +332,7 @@ func (r *Runtime) regexpproto_stdMatcherGeneric(rxObj *Object, arg Value) Value
 			if res == _null {
 				break
 			}
-			matchStr := nilSafe(r.toObject(res).self.get(intToValue(0))).ToString()
+			matchStr := nilSafe(r.toObject(res).self.get(intToValue(0))).toString()
 			a = append(a, matchStr)
 			if matchStr.length() == 0 {
 				thisIndex := rx.getStr("lastIndex").ToInteger()
@@ -368,7 +368,7 @@ func (r *Runtime) checkStdRegexp(rxObj *Object) *regexpObject {
 
 func (r *Runtime) regexpproto_stdMatcher(call FunctionCall) Value {
 	thisObj := r.toObject(call.This)
-	s := call.Argument(0).ToString()
+	s := call.Argument(0).toString()
 	rx := r.checkStdRegexp(thisObj)
 	if rx == nil {
 		return r.regexpproto_stdMatcherGeneric(thisObj, s)
@@ -421,7 +421,7 @@ func (r *Runtime) regexpproto_stdSearchGeneric(rxObj *Object, arg valueString) V
 
 func (r *Runtime) regexpproto_stdSearch(call FunctionCall) Value {
 	thisObj := r.toObject(call.This)
-	s := call.Argument(0).ToString()
+	s := call.Argument(0).toString()
 	rx := r.checkStdRegexp(thisObj)
 	if rx == nil {
 		return r.regexpproto_stdSearchGeneric(thisObj, s)
@@ -496,7 +496,7 @@ func (r *Runtime) regexpproto_stdSplitterGeneric(splitter *Object, s valueString
 func (r *Runtime) regexpproto_stdSplitter(call FunctionCall) Value {
 	rxObj := r.toObject(call.This)
 	c := r.speciesConstructor(rxObj, r.global.RegExp)
-	flags := nilSafe(rxObj.self.getStr("flags")).ToString()
+	flags := nilSafe(rxObj.self.getStr("flags")).toString()
 
 	// Add 'y' flag if missing
 	if flagsStr := flags.String(); !strings.Contains(flagsStr, "y") {
@@ -504,7 +504,7 @@ func (r *Runtime) regexpproto_stdSplitter(call FunctionCall) Value {
 	}
 	splitter := c([]Value{rxObj, flags})
 
-	s := call.Argument(0).ToString()
+	s := call.Argument(0).toString()
 	limitValue := call.Argument(1)
 	search := r.checkStdRegexp(splitter)
 	if search == nil {

+ 1 - 1
builtin_set.go

@@ -134,7 +134,7 @@ func (r *Runtime) builtin_newSet(args []Value) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := so.getStr("add")
-			iter := r.getIterator(arg.ToObject(r), nil)
+			iter := r.getIterator(arg, nil)
 			if adder == r.global.setAdder {
 				r.iterate(iter, func(item Value) {
 					so.m.set(item, nil)

+ 23 - 23
builtin_string.go

@@ -27,7 +27,7 @@ func toString(arg Value) valueString {
 	if s, ok := arg.(*valueSymbol); ok {
 		return newStringValue(s.descString())
 	}
-	return arg.ToString()
+	return arg.toString()
 }
 
 func (r *Runtime) builtin_String(call FunctionCall) Value {
@@ -123,7 +123,7 @@ func (r *Runtime) string_fromcharcode(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_charAt(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 	pos := call.Argument(0).ToInteger()
 	if pos < 0 || pos >= s.length() {
 		return stringEmpty
@@ -133,7 +133,7 @@ func (r *Runtime) stringproto_charAt(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_charCodeAt(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 	pos := call.Argument(0).ToInteger()
 	if pos < 0 || pos >= s.length() {
 		return _NaN
@@ -144,11 +144,11 @@ func (r *Runtime) stringproto_charCodeAt(call FunctionCall) Value {
 func (r *Runtime) stringproto_concat(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
 	strs := make([]valueString, len(call.Arguments)+1)
-	strs[0] = call.This.ToString()
+	strs[0] = call.This.toString()
 	_, allAscii := strs[0].(asciiString)
 	totalLen := strs[0].length()
 	for i, arg := range call.Arguments {
-		s := arg.ToString()
+		s := arg.toString()
 		if allAscii {
 			_, allAscii = s.(asciiString)
 		}
@@ -183,8 +183,8 @@ func (r *Runtime) stringproto_concat(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_indexOf(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	value := call.This.ToString()
-	target := call.Argument(0).ToString()
+	value := call.This.toString()
+	target := call.Argument(0).toString()
 	pos := call.Argument(1).ToInteger()
 
 	if pos < 0 {
@@ -201,8 +201,8 @@ func (r *Runtime) stringproto_indexOf(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_lastIndexOf(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	value := call.This.ToString()
-	target := call.Argument(0).ToString()
+	value := call.This.toString()
+	target := call.Argument(0).toString()
 	numPos := call.Argument(1).ToNumber()
 
 	var pos int64
@@ -234,7 +234,7 @@ func (r *Runtime) stringproto_match(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
 	regexp := call.Argument(0)
 	if regexp != _undefined && regexp != _null {
-		if matcher := toMethod(regexp.ToObject(r).self.get(symMatch)); matcher != nil {
+		if matcher := toMethod(r.getV(regexp, symMatch)); matcher != nil {
 			return matcher(FunctionCall{
 				This:      regexp,
 				Arguments: []Value{call.This},
@@ -254,7 +254,7 @@ func (r *Runtime) stringproto_match(call FunctionCall) Value {
 	if matcher, ok := r.toObject(rx.getSym(symMatch)).self.assertCallable(); ok {
 		return matcher(FunctionCall{
 			This:      rx.val,
-			Arguments: []Value{call.This.ToString()},
+			Arguments: []Value{call.This.toString()},
 		})
 	}
 
@@ -266,7 +266,7 @@ func (r *Runtime) stringproto_replace(call FunctionCall) Value {
 	searchValue := call.Argument(0)
 	replaceValue := call.Argument(1)
 	if searchValue != _undefined && searchValue != _null {
-		if replacer := toMethod(searchValue.ToObject(r).self.get(symReplace)); replacer != nil {
+		if replacer := toMethod(r.getV(searchValue, symReplace)); replacer != nil {
 			return replacer(FunctionCall{
 				This:      searchValue,
 				Arguments: []Value{call.This, replaceValue},
@@ -274,7 +274,7 @@ func (r *Runtime) stringproto_replace(call FunctionCall) Value {
 		}
 	}
 
-	s := call.This.ToString()
+	s := call.This.toString()
 	var str string
 	var isASCII bool
 	if astr, ok := s.(asciiString); ok {
@@ -417,7 +417,7 @@ func (r *Runtime) stringproto_search(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
 	regexp := call.Argument(0)
 	if regexp != _undefined && regexp != _null {
-		if searcher := toMethod(regexp.ToObject(r).self.get(symSearch)); searcher != nil {
+		if searcher := toMethod(r.getV(regexp, symSearch)); searcher != nil {
 			return searcher(FunctionCall{
 				This:      regexp,
 				Arguments: []Value{call.This},
@@ -437,7 +437,7 @@ func (r *Runtime) stringproto_search(call FunctionCall) Value {
 	if searcher, ok := r.toObject(rx.getSym(symSearch)).self.assertCallable(); ok {
 		return searcher(FunctionCall{
 			This:      rx.val,
-			Arguments: []Value{call.This.ToString()},
+			Arguments: []Value{call.This.toString()},
 		})
 	}
 
@@ -446,7 +446,7 @@ func (r *Runtime) stringproto_search(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_slice(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	l := s.length()
 	start := call.Argument(0).ToInteger()
@@ -490,14 +490,14 @@ func (r *Runtime) stringproto_split(call FunctionCall) Value {
 	separatorValue := call.Argument(0)
 	limitValue := call.Argument(1)
 	if separatorValue != _undefined && separatorValue != _null {
-		if splitter := toMethod(separatorValue.ToObject(r).self.get(symSplit)); splitter != nil {
+		if splitter := toMethod(r.getV(separatorValue, symSplit)); splitter != nil {
 			return splitter(FunctionCall{
 				This:      separatorValue,
 				Arguments: []Value{call.This, limitValue},
 			})
 		}
 	}
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	limit := -1
 	if limitValue != _undefined {
@@ -541,7 +541,7 @@ func (r *Runtime) stringproto_split(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_substring(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	l := s.length()
 	intStart := call.Argument(0).ToInteger()
@@ -572,27 +572,27 @@ func (r *Runtime) stringproto_substring(call FunctionCall) Value {
 
 func (r *Runtime) stringproto_toLowerCase(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	return s.toLower()
 }
 
 func (r *Runtime) stringproto_toUpperCase(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	return s.toUpper()
 }
 
 func (r *Runtime) stringproto_trim(call FunctionCall) Value {
 	r.checkObjectCoercible(call.This)
-	s := call.This.ToString()
+	s := call.This.toString()
 
 	return newStringValue(strings.Trim(s.String(), parser.WhitespaceChars))
 }
 
 func (r *Runtime) stringproto_substr(call FunctionCall) Value {
-	s := call.This.ToString()
+	s := call.This.toString()
 	start := call.Argument(0).ToInteger()
 	var length int64
 	sl := int64(s.length())

+ 2 - 2
builtin_symbol.go

@@ -17,7 +17,7 @@ var (
 func (r *Runtime) builtin_symbol(call FunctionCall) Value {
 	desc := ""
 	if arg := call.Argument(0); !IsUndefined(arg) {
-		desc = arg.ToString().String()
+		desc = arg.toString().String()
 	}
 	return &valueSymbol{
 		desc: desc,
@@ -59,7 +59,7 @@ func (r *Runtime) symbolproto_valueOf(call FunctionCall) Value {
 }
 
 func (r *Runtime) symbol_for(call FunctionCall) Value {
-	key := call.Argument(0).ToString().String()
+	key := call.Argument(0).toString().String()
 	if v := r.symbolRegistry[key]; v != nil {
 		return v
 	}

+ 1 - 1
builtin_weakmap.go

@@ -146,7 +146,7 @@ func (r *Runtime) builtin_newWeakMap(args []Value) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := wmo.getStr("set")
-			iter := r.getIterator(arg.ToObject(r), nil)
+			iter := r.getIterator(arg, nil)
 			i0 := intToValue(0)
 			i1 := intToValue(1)
 			if adder == r.global.weakMapAdder {

+ 1 - 1
builtin_weakset.go

@@ -107,7 +107,7 @@ func (r *Runtime) populateWeakSetGeneric(s *Object, adderValue Value, iterable V
 	if adder == nil {
 		panic(r.NewTypeError("WeakSet.add is not set"))
 	}
-	iter := r.getIterator(iterable.ToObject(r), nil)
+	iter := r.getIterator(iterable, nil)
 	r.iterate(iter, func(val Value) {
 		adder(FunctionCall{This: s, Arguments: []Value{val}})
 	})

+ 33 - 14
object.go

@@ -125,10 +125,11 @@ type objectImpl interface {
 	deleteStr(name string, throw bool) bool
 	delete(name Value, throw bool) bool
 	proto() *Object
+	setProto(proto *Object) *Object
 	hasInstance(v Value) bool
 	isExtensible() bool
 	preventExtensions()
-	enumerate(all, recusrive bool) iterNextFunc
+	enumerate(all, recursive bool) iterNextFunc
 	_enumerate(recursive bool) iterNextFunc
 	export() interface{}
 	exportType() reflect.Type
@@ -269,7 +270,7 @@ func (o *baseObject) get(n Value) Value {
 
 func (o *baseObject) checkDeleteProp(name string, prop *valueProperty, throw bool) bool {
 	if !prop.configurable {
-		o.val.runtime.typeErrorResult(throw, "Cannot delete property '%s' of %s", name, o.val.ToString())
+		o.val.runtime.typeErrorResult(throw, "Cannot delete property '%s' of %s", name, o.val.toString())
 		return false
 	}
 	return true
@@ -344,6 +345,24 @@ func (o *baseObject) getOwnProp(name Value) Value {
 	return o.val.self.getOwnPropStr(name.String())
 }
 
+func (o *baseObject) setProto(proto *Object) *Object {
+	current := o.prototype
+	if current.SameAs(proto) {
+		return nil
+	}
+	if !o.extensible {
+		return o.val.runtime.NewTypeError("%s is not extensible", o.val)
+	}
+	for p := proto; p != nil; {
+		if p.SameAs(o.val) {
+			return o.val.runtime.NewTypeError("Cyclic __proto__ value")
+		}
+		p = p.self.proto()
+	}
+	o.prototype = proto
+	return nil
+}
+
 func (o *baseObject) putStr(name string, val Value, throw bool) {
 	if v, exists := o.values[name]; exists {
 		if prop, ok := v.(*valueProperty); ok {
@@ -359,18 +378,17 @@ func (o *baseObject) putStr(name string, val Value, throw bool) {
 	}
 
 	if name == __proto__ {
-		if !o.extensible {
-			o.val.runtime.typeErrorResult(throw, "%s is not extensible", o.val)
-			return
-		}
-		if val == _undefined || val == _null {
-			o.prototype = nil
-			return
-		} else {
-			if val, ok := val.(*Object); ok {
-				o.prototype = val
+		var proto *Object
+		if val != _null {
+			if obj, ok := val.(*Object); ok {
+				proto = obj
+			} else {
+				return
 			}
 		}
+		if ex := o.setProto(proto); ex != nil {
+			panic(ex)
+		}
 		return
 	}
 
@@ -556,12 +574,13 @@ func (o *baseObject) _defineOwnProperty(name, existingValue Value, descr propert
 	return existing, true
 
 Reject:
-	o.val.runtime.typeErrorResult(throw, "Cannot redefine property: %s", name.ToString())
+	o.val.runtime.typeErrorResult(throw, "Cannot redefine property: %s", name.toString())
 	return nil, false
 
 }
 
 func (o *baseObject) defineOwnProperty(n Value, descr propertyDescr, throw bool) bool {
+	n = toPropertyKey(n)
 	if s, ok := n.(*valueSymbol); ok {
 		existingVal := o.symValues[s]
 		if v, ok := o._defineOwnProperty(n, existingVal, descr, throw); ok {
@@ -832,7 +851,7 @@ func (o *baseObject) getOwnSymbols() (res []Value) {
 }
 
 func (o *baseObject) hasInstance(Value) bool {
-	panic(o.val.runtime.NewTypeError("Expecting a function in instanceof check, but got %s", o.val.ToString()))
+	panic(o.val.runtime.NewTypeError("Expecting a function in instanceof check, but got %s", o.val.toString()))
 }
 
 func toMethod(v Value) func(FunctionCall) Value {

+ 1 - 1
object_goreflect.go

@@ -322,7 +322,7 @@ func (o *objectGoReflect) toPrimitiveNumber() Value {
 
 func (o *objectGoReflect) toPrimitiveString() Value {
 	if v := o._toNumber(); v != nil {
-		return v.ToString()
+		return v.toString()
 	}
 	return o._toString()
 }

+ 6 - 0
object_lazy.go

@@ -193,6 +193,12 @@ func (o *lazyObject) getOwnSymbols() []Value {
 	return obj.getOwnSymbols()
 }
 
+func (o *lazyObject) setProto(proto *Object) *Object {
+	obj := o.create(o.val)
+	o.val.self = obj
+	return obj.setProto(proto)
+}
+
 func (o *lazyObject) sortLen() int64 {
 	obj := o.create(o.val)
 	o.val.self = obj

+ 1 - 1
object_test.go

@@ -153,7 +153,7 @@ func BenchmarkToString1(b *testing.B) {
 	v := asciiString("test")
 
 	for i := 0; i < b.N; i++ {
-		v.ToString()
+		v.toString()
 	}
 }
 

+ 29 - 7
runtime.go

@@ -600,9 +600,9 @@ func (r *Runtime) error_toString(call FunctionCall) Value {
 		return newStringValue(fmt.Sprintf("%s: %s", name.String(), msgStr))
 	} else {
 		if nameStr != "" {
-			return name.ToString()
+			return name.toString()
 		} else {
-			return msg.ToString()
+			return msg.toString()
 		}
 	}
 }
@@ -707,7 +707,7 @@ func (r *Runtime) toCallable(v Value) func(FunctionCall) Value {
 	if call, ok := r.toObject(v).self.assertCallable(); ok {
 		return call
 	}
-	r.typeErrorResult(true, "Value is not callable: %s", v.ToString())
+	r.typeErrorResult(true, "Value is not callable: %s", v.toString())
 	return nil
 }
 
@@ -1292,11 +1292,11 @@ func (r *Runtime) toReflectValue(v Value, typ reflect.Type) (reflect.Value, erro
 	}
 
 	if typ == typeTime && et.Kind() == reflect.String {
-		time, ok := dateParse(v.String())
+		tme, ok := dateParse(v.String())
 		if !ok {
 			return reflect.Value{}, fmt.Errorf("Could not convert string %v to %v", v, typ)
 		}
-		return reflect.ValueOf(time), nil
+		return reflect.ValueOf(tme), nil
 	}
 
 	switch typ.Kind() {
@@ -1624,9 +1624,31 @@ func (r *Runtime) returnThis(call FunctionCall) Value {
 	return call.This
 }
 
-func (r *Runtime) getIterator(obj *Object, method func(FunctionCall) Value) *Object {
+func toPropertyKey(key Value) Value {
+	return key.ToPrimitiveString()
+}
+
+func (r *Runtime) getVStr(v Value, p string) Value {
+	o := v.ToObject(r)
+	prop := o.self.getPropStr(p)
+	if prop, ok := prop.(*valueProperty); ok {
+		return prop.get(v)
+	}
+	return prop
+}
+
+func (r *Runtime) getV(v Value, p Value) Value {
+	o := v.ToObject(r)
+	prop := o.self.getProp(p)
+	if prop, ok := prop.(*valueProperty); ok {
+		return prop.get(v)
+	}
+	return prop
+}
+
+func (r *Runtime) getIterator(obj Value, method func(FunctionCall) Value) *Object {
 	if method == nil {
-		method = toMethod(obj.self.get(symIterator))
+		method = toMethod(r.getV(obj, symIterator))
 		if method == nil {
 			panic(r.NewTypeError("object is not iterable"))
 		}

+ 70 - 0
runtime_test.go

@@ -1348,6 +1348,76 @@ func TestFreezeSymbol(t *testing.T) {
 	testScript1(SCRIPT, valueTrue, t)
 }
 
+func TestToPropertyKey(t *testing.T) {
+	const SCRIPT = `
+	var sym = Symbol(42);
+	var callCount = 0;
+
+	var wrapper = {
+	  toString: function() {
+		callCount += 1;
+		return sym;
+	  },
+	  valueOf: function() {
+		$ERROR("valueOf() called");
+	  }
+	};
+
+	var o = {};
+	o[wrapper] = function() { return "test" };
+	assert.sameValue(o[wrapper], o[sym], "o[wrapper] === o[sym]");
+	assert.sameValue(o[wrapper](), "test", "o[wrapper]()");
+	assert.sameValue(o[sym](), "test", "o[sym]()");
+	`
+
+	testScript1(TESTLIB+SCRIPT, _undefined, t)
+}
+
+func TestPrimThisValue(t *testing.T) {
+	const SCRIPT = `
+	function t() {
+		'use strict';
+
+		Boolean.prototype.toString = function() {
+		  return typeof this;
+		};
+
+		assert.sameValue(true.toLocaleString(), "boolean");
+
+		Boolean.prototype[Symbol.iterator] = function() {
+			return [typeof this][Symbol.iterator]();
+		}
+		var s = new Set(true);
+		assert.sameValue(s.size, 1, "size");
+		assert.sameValue(s.has("boolean"), true, "s.has('boolean')");
+	}
+	t();
+	`
+
+	testScript1(TESTLIB+SCRIPT, _undefined, t)
+}
+
+func TestPrimThisValueGetter(t *testing.T) {
+	const SCRIPT = `
+	function t() {
+		'use strict';
+		Object.defineProperty(Boolean.prototype, "toString", {
+		  get: function() {
+			var v = typeof this;
+			return function() {
+			  return v;
+			};
+		  }
+		});
+
+		assert.sameValue(true.toLocaleString(), "boolean");
+	}
+	t();
+	`
+
+	testScript1(TESTLIB+SCRIPT, _undefined, t)
+}
+
 /*
 func TestArrayConcatSparse(t *testing.T) {
 function foo(a,b,c)

+ 5 - 1
string_ascii.go

@@ -104,7 +104,11 @@ func (s asciiString) ToInteger() int64 {
 	return i
 }
 
-func (s asciiString) ToString() valueString {
+func (s asciiString) toString() valueString {
+	return s
+}
+
+func (s asciiString) ToPrimitiveString() Value {
 	return s
 }
 

+ 5 - 1
string_unicode.go

@@ -81,7 +81,11 @@ func (s unicodeString) ToInteger() int64 {
 	return 0
 }
 
-func (s unicodeString) ToString() valueString {
+func (s unicodeString) toString() valueString {
+	return s
+}
+
+func (s unicodeString) ToPrimitiveString() Value {
 	return s
 }
 

+ 12 - 7
tc39_test.go

@@ -50,6 +50,7 @@ var (
 		"test/built-ins/WeakMap/proto-from-ctor-realm.js":         true,
 		"test/built-ins/Map/proto-from-ctor-realm.js":             true,
 		"test/built-ins/Set/proto-from-ctor-realm.js":             true,
+		"test/built-ins/Object/proto-from-ctor.js":                true,
 
 		// class
 		"test/language/statements/class/subclass/builtin-objects/Symbol/symbol-valid-as-extends-value.js": true,
@@ -62,12 +63,18 @@ var (
 		"test/language/statements/class/subclass/builtin-objects/Map/regular-subclassing.js":              true,
 		"test/language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js":             true,
 		"test/language/statements/class/subclass/builtin-objects/Set/regular-subclassing.js":              true,
+		"test/language/statements/class/subclass/builtin-objects/Object/replacing-prototype.js":           true,
+		"test/language/statements/class/subclass/builtin-objects/Object/regular-subclassing.js":           true,
 
 		// Proxy
-		"test/built-ins/Object/prototype/toString/proxy-revoked.js":  true,
-		"test/built-ins/Object/prototype/toString/proxy-function.js": true,
-		"test/built-ins/Object/prototype/toString/proxy-array.js":    true,
-		"test/built-ins/JSON/stringify/value-proxy.js":               true,
+		"test/built-ins/Object/prototype/toString/proxy-revoked.js":    true,
+		"test/built-ins/Object/prototype/toString/proxy-function.js":   true,
+		"test/built-ins/Object/prototype/toString/proxy-array.js":      true,
+		"test/built-ins/JSON/stringify/value-proxy.js":                 true,
+		"test/built-ins/Object/setPrototypeOf/set-error.js":            true,
+		"test/built-ins/Object/assign/source-own-prop-keys-error.js":   true,
+		"test/built-ins/Object/assign/source-own-prop-error.js":        true,
+		"test/built-ins/Object/assign/source-own-prop-desc-missing.js": true,
 
 		// Arrow functions
 		"test/built-ins/Set/prototype/forEach/this-arg-explicit-cannot-override-lexical-this-arrow.js": true,
@@ -84,9 +91,7 @@ var (
 	es6IdWhiteList = []string{
 		"12.9.3",
 		"12.9.4",
-		"19.1.2.8",
-		"19.1.2.5",
-		"19.1.3.6",
+		"19.1",
 		"19.4",
 		"21.1.3.14",
 		"21.1.3.15",

+ 62 - 24
value.go

@@ -41,7 +41,8 @@ var (
 
 type Value interface {
 	ToInteger() int64
-	ToString() valueString
+	toString() valueString
+	ToPrimitiveString() Value
 	String() string
 	ToFloat() float64
 	ToNumber() Value
@@ -103,7 +104,7 @@ func propGetter(o Value, v Value, r *Runtime) *Object {
 			return obj
 		}
 	}
-	r.typeErrorResult(true, "Getter must be a function: %s", v.ToString())
+	r.typeErrorResult(true, "Getter must be a function: %s", v.toString())
 	return nil
 }
 
@@ -116,7 +117,7 @@ func propSetter(o Value, v Value, r *Runtime) *Object {
 			return obj
 		}
 	}
-	r.typeErrorResult(true, "Setter must be a function: %s", v.ToString())
+	r.typeErrorResult(true, "Setter must be a function: %s", v.toString())
 	return nil
 }
 
@@ -124,10 +125,14 @@ func (i valueInt) ToInteger() int64 {
 	return int64(i)
 }
 
-func (i valueInt) ToString() valueString {
+func (i valueInt) toString() valueString {
 	return asciiString(i.String())
 }
 
+func (i valueInt) ToPrimitiveString() Value {
+	return i
+}
+
 func (i valueInt) String() string {
 	return strconv.FormatInt(int64(i), 10)
 }
@@ -218,13 +223,17 @@ func (o valueBool) ToInteger() int64 {
 	return 0
 }
 
-func (o valueBool) ToString() valueString {
+func (o valueBool) toString() valueString {
 	if o {
 		return stringTrue
 	}
 	return stringFalse
 }
 
+func (o valueBool) ToPrimitiveString() Value {
+	return o
+}
+
 func (o valueBool) String() string {
 	if o {
 		return "true"
@@ -316,18 +325,26 @@ func (n valueNull) ToInteger() int64 {
 	return 0
 }
 
-func (n valueNull) ToString() valueString {
+func (n valueNull) toString() valueString {
 	return stringNull
 }
 
+func (n valueNull) ToPrimitiveString() Value {
+	return n
+}
+
 func (n valueNull) String() string {
 	return "null"
 }
 
-func (u valueUndefined) ToString() valueString {
+func (u valueUndefined) toString() valueString {
 	return stringUndefined
 }
 
+func (u valueUndefined) ToPrimitiveString() Value {
+	return u
+}
+
 func (u valueUndefined) String() string {
 	return "undefined"
 }
@@ -402,7 +419,7 @@ func (n valueNull) assertString() (valueString, bool) {
 	return nil, false
 }
 
-func (n valueNull) baseObject(r *Runtime) *Object {
+func (n valueNull) baseObject(*Runtime) *Object {
 	return nil
 }
 
@@ -422,10 +439,14 @@ func (p *valueProperty) ToInteger() int64 {
 	return 0
 }
 
-func (p *valueProperty) ToString() valueString {
+func (p *valueProperty) toString() valueString {
 	return stringEmpty
 }
 
+func (p *valueProperty) ToPrimitiveString() Value {
+	return _undefined
+}
+
 func (p *valueProperty) String() string {
 	return ""
 }
@@ -438,7 +459,7 @@ func (p *valueProperty) ToBoolean() bool {
 	return false
 }
 
-func (p *valueProperty) ToObject(r *Runtime) *Object {
+func (p *valueProperty) ToObject(*Runtime) *Object {
 	return nil
 }
 
@@ -494,11 +515,11 @@ func (p *valueProperty) SameAs(other Value) bool {
 	return false
 }
 
-func (p *valueProperty) Equals(other Value) bool {
+func (p *valueProperty) Equals(Value) bool {
 	return false
 }
 
-func (p *valueProperty) StrictEquals(other Value) bool {
+func (p *valueProperty) StrictEquals(Value) bool {
 	return false
 }
 
@@ -531,10 +552,14 @@ func (f valueFloat) ToInteger() int64 {
 	return int64(f)
 }
 
-func (f valueFloat) ToString() valueString {
+func (f valueFloat) toString() valueString {
 	return asciiString(f.String())
 }
 
+func (f valueFloat) ToPrimitiveString() Value {
+	return f
+}
+
 var matchLeading0Exponent = regexp.MustCompile(`([eE][+\-])0+([1-9])`) // 1e-07 => 1e-7
 
 func (f valueFloat) String() string {
@@ -663,8 +688,12 @@ func (o *Object) ToInteger() int64 {
 	return o.self.toPrimitiveNumber().ToNumber().ToInteger()
 }
 
-func (o *Object) ToString() valueString {
-	return o.self.toPrimitiveString().ToString()
+func (o *Object) toString() valueString {
+	return o.self.toPrimitiveString().toString()
+}
+
+func (o *Object) ToPrimitiveString() Value {
+	return o.self.toPrimitiveString().ToPrimitiveString()
 }
 
 func (o *Object) String() string {
@@ -679,7 +708,7 @@ func (o *Object) ToBoolean() bool {
 	return true
 }
 
-func (o *Object) ToObject(r *Runtime) *Object {
+func (o *Object) ToObject(*Runtime) *Object {
 	return o
 }
 
@@ -736,7 +765,7 @@ func (o *Object) assertString() (valueString, bool) {
 	return nil, false
 }
 
-func (o *Object) baseObject(r *Runtime) *Object {
+func (o *Object) baseObject(*Runtime) *Object {
 	return o
 }
 
@@ -827,7 +856,12 @@ func (o valueUnresolved) ToInteger() int64 {
 	return 0
 }
 
-func (o valueUnresolved) ToString() valueString {
+func (o valueUnresolved) toString() valueString {
+	o.throw()
+	return nil
+}
+
+func (o valueUnresolved) ToPrimitiveString() Value {
 	o.throw()
 	return nil
 }
@@ -847,7 +881,7 @@ func (o valueUnresolved) ToBoolean() bool {
 	return false
 }
 
-func (o valueUnresolved) ToObject(r *Runtime) *Object {
+func (o valueUnresolved) ToObject(*Runtime) *Object {
 	o.throw()
 	return nil
 }
@@ -857,17 +891,17 @@ func (o valueUnresolved) ToNumber() Value {
 	return nil
 }
 
-func (o valueUnresolved) SameAs(other Value) bool {
+func (o valueUnresolved) SameAs(Value) bool {
 	o.throw()
 	return false
 }
 
-func (o valueUnresolved) Equals(other Value) bool {
+func (o valueUnresolved) Equals(Value) bool {
 	o.throw()
 	return false
 }
 
-func (o valueUnresolved) StrictEquals(other Value) bool {
+func (o valueUnresolved) StrictEquals(Value) bool {
 	o.throw()
 	return false
 }
@@ -887,7 +921,7 @@ func (o valueUnresolved) assertString() (valueString, bool) {
 	return nil, false
 }
 
-func (o valueUnresolved) baseObject(r *Runtime) *Object {
+func (o valueUnresolved) baseObject(*Runtime) *Object {
 	o.throw()
 	return nil
 }
@@ -911,10 +945,14 @@ func (s *valueSymbol) ToInteger() int64 {
 	panic(typeError("Cannot convert a Symbol value to a number"))
 }
 
-func (s *valueSymbol) ToString() valueString {
+func (s *valueSymbol) toString() valueString {
 	panic(typeError("Cannot convert a Symbol value to a string"))
 }
 
+func (s *valueSymbol) ToPrimitiveString() Value {
+	return s
+}
+
 func (s *valueSymbol) String() string {
 	return s.descString()
 }

+ 11 - 12
vm.go

@@ -463,7 +463,7 @@ func (vm *vm) toCallee(v Value) *Object {
 	case memberUnresolved:
 		panic(vm.r.NewTypeError("Object has no member '%s'", unresolved.ref))
 	}
-	panic(vm.r.NewTypeError("Value is not an object: %s", v.ToString()))
+	panic(vm.r.NewTypeError("Value is not an object: %s", v.toString()))
 }
 
 type _newStash struct{}
@@ -600,10 +600,10 @@ func (_add) exec(vm *vm) {
 
 	if isLeftString || isRightString {
 		if !isLeftString {
-			leftString = left.ToString()
+			leftString = left.toString()
 		}
 		if !isRightString {
-			rightString = right.ToString()
+			rightString = right.toString()
 		}
 		ret = leftString.concat(rightString)
 	} else {
@@ -950,7 +950,7 @@ var setElem _setElem
 
 func (_setElem) exec(vm *vm) {
 	obj := vm.stack[vm.sp-3].ToObject(vm.r)
-	propName := vm.stack[vm.sp-2]
+	propName := toPropertyKey(vm.stack[vm.sp-2])
 	val := vm.stack[vm.sp-1]
 
 	obj.self.put(propName, val, false)
@@ -966,7 +966,7 @@ var setElemStrict _setElemStrict
 
 func (_setElemStrict) exec(vm *vm) {
 	obj := vm.r.toObject(vm.stack[vm.sp-3])
-	propName := vm.stack[vm.sp-2]
+	propName := toPropertyKey(vm.stack[vm.sp-2])
 	val := vm.stack[vm.sp-1]
 
 	obj.self.put(propName, val, true)
@@ -982,7 +982,7 @@ var deleteElem _deleteElem
 
 func (_deleteElem) exec(vm *vm) {
 	obj := vm.r.toObject(vm.stack[vm.sp-2])
-	propName := vm.stack[vm.sp-1]
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if !obj.self.hasProperty(propName) || obj.self.delete(propName, false) {
 		vm.stack[vm.sp-2] = valueTrue
 	} else {
@@ -998,7 +998,7 @@ var deleteElemStrict _deleteElemStrict
 
 func (_deleteElemStrict) exec(vm *vm) {
 	obj := vm.r.toObject(vm.stack[vm.sp-2])
-	propName := vm.stack[vm.sp-1]
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	obj.self.delete(propName, true)
 	vm.stack[vm.sp-2] = valueTrue
 	vm.sp--
@@ -1154,7 +1154,7 @@ var getElem _getElem
 func (_getElem) exec(vm *vm) {
 	v := vm.stack[vm.sp-2]
 	obj := v.baseObject(vm.r)
-	propName := vm.stack[vm.sp-1]
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if obj == nil {
 		panic(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
 	}
@@ -1180,10 +1180,9 @@ var getElemCallee _getElemCallee
 func (_getElemCallee) exec(vm *vm) {
 	v := vm.stack[vm.sp-2]
 	obj := v.baseObject(vm.r)
-	propName := vm.stack[vm.sp-1]
+	propName := toPropertyKey(vm.stack[vm.sp-1])
 	if obj == nil {
-		vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", propName.String())
-		panic("Unreachable")
+		panic(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
 	}
 
 	prop := obj.self.getProp(propName)
@@ -1735,7 +1734,7 @@ repeat:
 		obj.self = f.create(obj)
 		goto repeat
 	default:
-		vm.r.typeErrorResult(true, "Not a function: %s", obj.ToString())
+		vm.r.typeErrorResult(true, "Not a function: %s", obj.toString())
 	}
 }
 

+ 2 - 2
vm_test.go

@@ -91,10 +91,10 @@ func f_add(vm *vm) {
 
 	if isLeftString || isRightString {
 		if !isLeftString {
-			leftString = left.ToString()
+			leftString = left.toString()
 		}
 		if !isRightString {
-			rightString = right.ToString()
+			rightString = right.toString()
 		}
 		ret = leftString.concat(rightString)
 	} else {