"src/harmony-array.js",
"src/harmony-typedarray.js",
"src/harmony-classes.js",
+ "src/harmony-tostring.js"
]
outputs = [
// Well-known symbols
static Local<Symbol> GetIterator(Isolate* isolate);
static Local<Symbol> GetUnscopables(Isolate* isolate);
+ static Local<Symbol> GetToStringTag(Isolate* isolate);
V8_INLINE static Symbol* Cast(v8::Value* obj);
}
+static bool GetPredefinedToString(i::Handle<i::String> tag,
+ Local<String>* result) {
+ i::Isolate* i_isolate = tag->GetIsolate();
+ Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
+ i::Factory* factory = i_isolate->factory();
+
+ if (i::String::Equals(tag, factory->Arguments_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Arguments]");
+ } else if (i::String::Equals(tag, factory->Array_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Array]");
+ } else if (i::String::Equals(tag, factory->Boolean_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Boolean]");
+ } else if (i::String::Equals(tag, factory->Date_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Date]");
+ } else if (i::String::Equals(tag, factory->Error_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Error]");
+ } else if (i::String::Equals(tag, factory->Function_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Function]");
+ } else if (i::String::Equals(tag, factory->Number_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~Number]");
+ } else if (i::String::Equals(tag, factory->RegExp_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~RegExp]");
+ } else if (i::String::Equals(tag, factory->String_string())) {
+ *result = v8::String::NewFromUtf8(isolate, "[object ~String]");
+ } else {
+ return false;
+ }
+ return true;
+}
+
+
Local<String> v8::Object::ObjectProtoToString() {
i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate();
Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name(self->class_name(), i_isolate);
+ i::Handle<i::Object> tag;
// Native implementation of Object.prototype.toString (v8natives.js):
// var c = %_ClassOf(this);
i_isolate->factory()->Arguments_string())) {
return v8::String::NewFromUtf8(isolate, "[object Object]");
} else {
+ if (internal::FLAG_harmony_tostring) {
+ i::Handle<i::Symbol> toStringTag =
+ Utils::OpenHandle(*Symbol::GetToStringTag(isolate));
+ EXCEPTION_PREAMBLE(i_isolate);
+ has_pending_exception =
+ !i::Runtime::GetObjectProperty(i_isolate, self, toStringTag)
+ .ToHandle(&tag);
+ EXCEPTION_BAILOUT_CHECK(i_isolate, Local<v8::String>());
+
+ if (!tag->IsUndefined()) {
+ if (!tag->IsString())
+ return v8::String::NewFromUtf8(isolate, "[object ???]");
+ i::Handle<i::String> tag_name = i::Handle<i::String>::cast(tag);
+ if (!i::String::Equals(class_name, tag_name)) {
+ Local<String> result;
+ if (GetPredefinedToString(tag_name, &result)) return result;
+
+ class_name = tag_name;
+ }
+ }
+ }
const char* prefix = "[object ";
Local<String> str = Utils::ToLocal(class_name);
const char* postfix = "]";
}
+Local<Symbol> v8::Symbol::GetToStringTag(Isolate* isolate) {
+ return GetWellKnownSymbol(isolate, "Symbol.toStringTag");
+}
+
+
Local<Private> v8::Private::New(Isolate* isolate, Local<String> name) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "Private::New()");
func = array.join;
}
if (!IS_SPEC_FUNCTION(func)) {
- return %_CallFunction(array, ObjectToString);
+ return %_CallFunction(array, NoSideEffectsObjectToString);
}
return %_CallFunction(array, func);
}
%AddNamedProperty(
$ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
+ %AddNamedProperty($ArrayBuffer.prototype,
+ symbolToStringTag, "ArrayBuffer", DONT_ENUM | READ_ONLY);
+
InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLen);
InstallFunctions($ArrayBuffer, DONT_ENUM, $Array(
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_regexps)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_arrow_functions)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_numeric_literals)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_tostring)
void Genesis::InstallNativeFunctions_harmony_proxies() {
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object_literals)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_arrow_functions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_numeric_literals)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tostring)
void Genesis::InitializeGlobal_harmony_regexps() {
Handle<JSObject> builtins(native_context()->builtins());
static const char* harmony_regexps_natives[] = {NULL};
static const char* harmony_arrow_functions_natives[] = {NULL};
static const char* harmony_numeric_literals_natives[] = {NULL};
+ static const char* harmony_tostring_natives[] = {"native harmony-tostring.js",
+ NULL};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
%SetCode($Set, SetConstructor);
%FunctionSetPrototype($Set, new $Object());
%AddNamedProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
+ %AddNamedProperty(
+ $Set.prototype, symbolToStringTag, "Set", DONT_ENUM | READ_ONLY);
%FunctionSetLength(SetForEach, 1);
%SetCode($Map, MapConstructor);
%FunctionSetPrototype($Map, new $Object());
%AddNamedProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
+ %AddNamedProperty(
+ $Map.prototype, symbolToStringTag, "Map", DONT_ENUM | READ_ONLY);
%FunctionSetLength(MapForEach, 1);
V(harmony_classes, "harmony classes") \
V(harmony_object_literals, "harmony object literal extensions") \
V(harmony_regexps, "reg-exp related harmony features") \
- V(harmony_arrow_functions, "harmony arrow functions")
+ V(harmony_arrow_functions, "harmony arrow functions") \
+ V(harmony_tostring, "harmony Symbol.toStringTag")
#define STAGED_FEATURES(V) \
V(harmony_numeric_literals, "harmony numeric literals (0o77, 0b11)")
GeneratorObjectIterator, DONT_ENUM | DONT_DELETE | READ_ONLY);
%AddNamedProperty(GeneratorObjectPrototype, "constructor",
GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %AddNamedProperty(GeneratorObjectPrototype,
+ symbolToStringTag, "Generator", DONT_ENUM | READ_ONLY);
%InternalSetPrototype(GeneratorFunctionPrototype, $Function.prototype);
%SetCode(GeneratorFunctionPrototype, GeneratorFunctionPrototypeConstructor);
%AddNamedProperty(GeneratorFunctionPrototype, "constructor",
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js and symbol.js:
+// var $Object = global.Object;
+// var $Symbol = global.Symbol;
+
+var symbolToStringTag = InternalSymbol("Symbol.toStringTag");
+
+var kBuiltinStringTags = {
+ "__proto__": null,
+ "Arguments": true,
+ "Array": true,
+ "Boolean": true,
+ "Date": true,
+ "Error": true,
+ "Function": true,
+ "Number": true,
+ "RegExp": true,
+ "String": true
+};
+
+DefaultObjectToString = ObjectToStringHarmony;
+// ES6 draft 08-24-14, section 19.1.3.6
+function ObjectToStringHarmony() {
+ if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
+ if (IS_NULL(this)) return "[object Null]";
+ var O = ToObject(this);
+ var builtinTag = %_ClassOf(O);
+ var tag = O[symbolToStringTag];
+ if (IS_UNDEFINED(tag)) {
+ tag = builtinTag;
+ } else if (!IS_STRING(tag)) {
+ return "[object ???]"
+ } else if (tag !== builtinTag && kBuiltinStringTags[tag]) {
+ return "[object ~" + tag + "]";
+ }
+ return "[object " + tag + "]";
+}
+
+function HarmonyToStringExtendSymbolPrototype() {
+ %CheckIsBootstrapping();
+
+ InstallConstants($Symbol, $Array(
+ // TODO(dslomov, caitp): Move to symbol.js when shipping
+ "toStringTag", symbolToStringTag
+ ));
+}
+
+HarmonyToStringExtendSymbolPrototype();
+
+function HarmonyToStringExtendObjectPrototype() {
+ %CheckIsBootstrapping();
+
+ // Set up the non-enumerable functions on the Array prototype object.
+ var desc = ToPropertyDescriptor({
+ value: ObjectToStringHarmony
+ });
+ DefineOwnProperty($Object.prototype, "toString", desc, false);
+}
+
+HarmonyToStringExtendObjectPrototype();
V(next_string, "next") \
V(byte_length_string, "byteLength") \
V(byte_offset_string, "byteOffset") \
- V(minus_zero_string, "-0")
+ V(minus_zero_string, "-0") \
+ V(Array_string, "Array") \
+ V(Error_string, "Error") \
+ V(RegExp_string, "RegExp")
#define PRIVATE_SYMBOL_LIST(V) \
V(frozen_symbol) \
return str;
}
if (IS_SYMBOL(obj)) return %_CallFunction(obj, SymbolToString);
- if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
+ if (IS_OBJECT(obj)
+ && %GetDataProperty(obj, "toString") === DefaultObjectToString) {
var constructor = %GetDataProperty(obj, "constructor");
if (typeof constructor == "function") {
var constructorName = constructor.name;
if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
return %_CallFunction(obj, ErrorToString);
}
- return %_CallFunction(obj, ObjectToString);
+
+ return %_CallFunction(obj, NoSideEffectsObjectToString);
}
// To determine whether we can safely stringify an object using ErrorToString
function ToDetailString(obj) {
- if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
+ if (obj != null && IS_OBJECT(obj) && obj.toString === DefaultObjectToString) {
var constructor = obj.constructor;
if (typeof constructor == "function") {
var constructorName = constructor.name;
var constructor = receiver.constructor;
if (!constructor) {
return requireConstructor ? null :
- %_CallFunction(receiver, ObjectToString);
+ %_CallFunction(receiver, NoSideEffectsObjectToString);
}
var constructorName = constructor.name;
if (!constructorName) {
return requireConstructor ? null :
- %_CallFunction(receiver, ObjectToString);
+ %_CallFunction(receiver, NoSideEffectsObjectToString);
}
return constructorName;
}
%CheckIsBootstrapping();
%AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);
+ %AddNamedProperty(
+ $Promise.prototype, symbolToStringTag, "Promise", DONT_ENUM | READ_ONLY);
InstallFunctions($Promise, DONT_ENUM, [
"defer", PromiseDeferred,
"accept", PromiseResolved,
// "isConcatSpreadable", symbolIsConcatSpreadable,
// "isRegExp", symbolIsRegExp,
"iterator", symbolIterator,
+ // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
+ // Move here when shipping
// "toStringTag", symbolToStringTag,
"unscopables", symbolUnscopables
));
));
%AddNamedProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
+ %AddNamedProperty(
+ $Symbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
"toString", SymbolToString,
"valueOf", SymbolValueOf
// ----------------------------------------------------------------------------
// Object
+var DefaultObjectToString = NoSideEffectsObjectToString;
// ECMA-262 - 15.2.4.2
-function ObjectToString() {
+function NoSideEffectsObjectToString() {
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
if (IS_NULL(this)) return "[object Null]";
return "[object " + %_ClassOf(ToObject(this)) + "]";
// Set up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array(
- "toString", ObjectToString,
+ "toString", NoSideEffectsObjectToString,
"toLocaleString", ObjectToLocaleString,
"valueOf", ObjectValueOf,
"hasOwnProperty", ObjectHasOwnProperty,
%SetCode($WeakMap, WeakMapConstructor);
%FunctionSetPrototype($WeakMap, new $Object());
%AddNamedProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
+ %AddNamedProperty(
+ $WeakMap.prototype, symbolToStringTag, "WeakMap", DONT_ENUM | READ_ONLY);
// Set up the non-enumerable functions on the WeakMap prototype object.
InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array(
%SetCode($WeakSet, WeakSetConstructor);
%FunctionSetPrototype($WeakSet, new $Object());
%AddNamedProperty($WeakSet.prototype, "constructor", $WeakSet, DONT_ENUM);
+ %AddNamedProperty(
+ $WeakSet.prototype, symbolToStringTag, "WeakSet", DONT_ENUM | READ_ONLY);
// Set up the non-enumerable functions on the WeakSet prototype object.
InstallFunctions($WeakSet.prototype, DONT_ENUM, $Array(
SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
}
+void SymbolAccessorGetterReturnsDefault(
+ Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+ CHECK(name->IsSymbol());
+ Local<Symbol> sym = Local<Symbol>::Cast(name);
+ if (sym->Name()->IsUndefined()) return;
+ info.GetReturnValue().Set(info.Data());
+}
+
+static void ThrowingSymbolAccessorGetter(
+ Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+ info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
+}
+
void EmptyInterceptorGetter(Local<String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
}
}
+TEST(ObjectProtoToStringES6) {
+ // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
+ i::FLAG_harmony_tostring = true;
+ LocalContext context;
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+ templ->SetClassName(v8_str("MyClass"));
+
+ Local<String> customized_tostring = v8_str("customized toString");
+
+ // Replace Object.prototype.toString
+ CompileRun(
+ "Object.prototype.toString = function() {"
+ " return 'customized toString';"
+ "}");
+
+ // Normal ToString call should call replaced Object.prototype.toString
+ Local<v8::Object> instance = templ->GetFunction()->NewInstance();
+ Local<String> value = instance->ToString();
+ CHECK(value->IsString() && value->Equals(customized_tostring));
+
+ // ObjectProtoToString should not call replace toString function.
+ value = instance->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
+
+ // Check global
+ value = context->Global()->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
+
+ // Check ordinary object
+ Local<Value> object = CompileRun("new Object()");
+ value = object.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
+
+ // Check that ES6 semantics using @@toStringTag work
+ Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
+
+#define TEST_TOSTRINGTAG(type, tag, expected) \
+ do { \
+ object = CompileRun("new " #type "()"); \
+ object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
+ value = object.As<v8::Object>()->ObjectProtoToString(); \
+ CHECK(value->IsString() && \
+ value->Equals(v8_str("[object " #expected "]"))); \
+ } while (0)
+
+ TEST_TOSTRINGTAG(Array, Object, Object);
+ TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
+ TEST_TOSTRINGTAG(Object, Array, ~Array);
+ TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
+ TEST_TOSTRINGTAG(Object, Date, ~Date);
+ TEST_TOSTRINGTAG(Object, Error, ~Error);
+ TEST_TOSTRINGTAG(Object, Function, ~Function);
+ TEST_TOSTRINGTAG(Object, Number, ~Number);
+ TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
+ TEST_TOSTRINGTAG(Object, String, ~String);
+ TEST_TOSTRINGTAG(Object, Foo, Foo);
+
+#undef TEST_TOSTRINGTAG
+
+ // @@toStringTag getter throws
+ Local<Value> obj = v8::Object::New(isolate);
+ obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
+ {
+ TryCatch try_catch;
+ value = obj.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ }
+
+ // @@toStringTag getter does not throw
+ obj = v8::Object::New(isolate);
+ obj.As<v8::Object>()->SetAccessor(
+ toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
+ {
+ TryCatch try_catch;
+ value = obj.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+ CHECK(!try_catch.HasCaught());
+ }
+
+ // JS @@toStringTag value
+ obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
+ {
+ TryCatch try_catch;
+ value = obj.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+ CHECK(!try_catch.HasCaught());
+ }
+
+ // JS @@toStringTag getter throws
+ obj = CompileRun(
+ "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+ " get: function() { throw 'Test'; }"
+ "}); obj");
+ {
+ TryCatch try_catch;
+ value = obj.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ }
+
+ // JS @@toStringTag getter does not throw
+ obj = CompileRun(
+ "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+ " get: function() { return 'Test'; }"
+ "}); obj");
+ {
+ TryCatch try_catch;
+ value = obj.As<v8::Object>()->ObjectProtoToString();
+ CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+ CHECK(!try_catch.HasCaught());
+ }
+}
+
+
THREADED_TEST(ObjectGetConstructorName) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
function assertSize(expected, collection) {
function TestPrototype(C) {
assertTrue(C.prototype instanceof Object);
assertEquals({
- value: {},
+ value: C.prototype,
writable: false,
enumerable: false,
configurable: false
}
TestMapConstructorIterableValue(Map);
TestMapConstructorIterableValue(WeakMap);
+
+function TestCollectionToString(C) {
+ assertEquals("[object " + C.name + "]",
+ Object.prototype.toString.call(new C()));
+}
+TestCollectionToString(Map);
+TestCollectionToString(Set);
+TestCollectionToString(WeakMap);
+TestCollectionToString(WeakSet);
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --harmony-scoping --allow-natives-syntax
+// Flags: --harmony-scoping --allow-natives-syntax --harmony-tostring
// Test instantations of generators.
assertTrue(iter instanceof g);
assertEquals("Generator", %_ClassOf(iter));
assertEquals("[object Generator]", String(iter));
+ assertEquals("[object Generator]", Object.prototype.toString.call(iter));
assertEquals([], Object.getOwnPropertyNames(iter));
assertTrue(iter !== new g());
}
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+var global = this;
+
+var funs = {
+ Object: [ Object ],
+ Function: [ Function ],
+ Array: [ Array ],
+ String: [ String ],
+ Boolean: [ Boolean ],
+ Number: [ Number ],
+ Date: [ Date ],
+ RegExp: [ RegExp ],
+ Error: [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
+ EvalError, URIError ]
+}
+for (f in funs) {
+ for (i in funs[f]) {
+ assertEquals("[object " + f + "]",
+ Object.prototype.toString.call(new funs[f][i]),
+ funs[f][i]);
+ assertEquals("[object Function]",
+ Object.prototype.toString.call(funs[f][i]),
+ funs[f][i]);
+ }
+}
+
+function testToStringTag(className) {
+ // Using builtin toStringTags
+ var obj = {};
+ obj[Symbol.toStringTag] = className;
+ assertEquals("[object ~" + className + "]",
+ Object.prototype.toString.call(obj));
+
+ // Getter throws
+ obj = {};
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ get: function() { throw className; }
+ });
+ assertThrows(function() {
+ Object.prototype.toString.call(obj);
+ }, className);
+
+ // Getter does not throw
+ obj = {};
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ get: function() { return className; }
+ });
+ assertEquals("[object ~" + className + "]",
+ Object.prototype.toString.call(obj));
+
+ // Custom, non-builtin toStringTags
+ obj = {};
+ obj[Symbol.toStringTag] = "X" + className;
+ assertEquals("[object X" + className + "]",
+ Object.prototype.toString.call(obj));
+
+ // With getter
+ obj = {};
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ get: function() { return "X" + className; }
+ });
+ assertEquals("[object X" + className + "]",
+ Object.prototype.toString.call(obj));
+
+ // Undefined toStringTag should return [object className]
+ var obj = className === "Arguments" ?
+ (function() { return arguments; })() : new global[className];
+ obj[Symbol.toStringTag] = undefined;
+ assertEquals("[object " + className + "]",
+ Object.prototype.toString.call(obj));
+
+ // With getter
+ var obj = className === "Arguments" ?
+ (function() { return arguments; })() : new global[className];
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ get: function() { return undefined; }
+ });
+ assertEquals("[object " + className + "]",
+ Object.prototype.toString.call(obj));
+}
+
+[
+ "Arguments",
+ "Array",
+ "Boolean",
+ "Date",
+ "Error",
+ "Function",
+ "Number",
+ "RegExp",
+ "String"
+].forEach(testToStringTag);
+
+function testToStringTagNonString(value) {
+ var obj = {};
+ obj[Symbol.toStringTag] = value;
+ assertEquals("[object ???]", Object.prototype.toString.call(obj));
+
+ // With getter
+ obj = {};
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ get: function() { return value; }
+ });
+ assertEquals("[object ???]", Object.prototype.toString.call(obj));
+}
+
+[
+ null,
+ function() {},
+ [],
+ {},
+ /regexp/,
+ 42,
+ Symbol("sym"),
+ new Date(),
+ (function() { return arguments; })(),
+ true,
+ new Error("oops"),
+ new String("str")
+].forEach(testToStringTagNonString);
+
+function testObjectToStringPropertyDesc() {
+ var desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString");
+ assertTrue(desc.writable);
+ assertFalse(desc.enumerable);
+ assertTrue(desc.configurable);
+}
+testObjectToStringPropertyDesc();
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
// Make sure we don't rely on functions patchable by monkeys.
var call = Function.prototype.call.call.bind(Function.prototype.call)
var observe = Object.observe;
-var getOwnPropertyNames = Object.getOwnPropertyNames
-var defineProperty = Object.defineProperty
+var getOwnPropertyNames = Object.getOwnPropertyNames;
+var defineProperty = Object.defineProperty;
+
+
+(function() {
+ // Test before clearing global (fails otherwise)
+ assertEquals("[object Promise]",
+ Object.prototype.toString.call(new Promise(function() {})));
+})();
+
function clear(o) {
if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
var symbols = []
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Flags: --harmony-tostring
+
// ArrayBuffer
function TestByteLength(param, expectedByteLength) {
var ab = new ArrayBuffer();
assertSame(0, ab.byteLength);
+ assertEquals("[object ArrayBuffer]",
+ Object.prototype.toString.call(ab));
}
TestArrayBufferCreation();
var ab = new ArrayBuffer(256*elementSize);
var a0 = new constr(30);
+ assertEquals("[object " + constr.name + "]",
+ Object.prototype.toString.call(a0));
+
assertTrue(ArrayBuffer.isView(a0));
assertSame(elementSize, a0.BYTES_PER_ELEMENT);
assertSame(30, a0.length);
'../../src/generator.js',
'../../src/harmony-string.js',
'../../src/harmony-array.js',
+ '../../src/harmony-tostring.js',
'../../src/harmony-typedarray.js',
'../../src/harmony-classes.js',
],