Fix Object.prototype.toString() when @@toStringTag is not a string.
ES2017 draft 19.1.3.6: If @@toStringTag is not a string, Object.prototype.toString() returns [object Object], except in the following cases: - Array - String - Arguments - Function - Error - Boolean - Number - Date - RegExp. For anything else, e.g., Maps, Sets, TypedArrays, or the global object, toString() returns [object Object] if @@toStringTag is absent or not a string. In order to be able to easily identify the global object in d8, we set @@toStringTag to "global" for d8. CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel BUG= Review-Url: https://codereview.chromium.org/2071343002 Cr-Commit-Position: refs/heads/master@{#37218}
This commit is contained in:
parent
5508e16592
commit
bdc78957e5
@ -1135,6 +1135,10 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
|
||||
String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
|
||||
.ToLocalChecked(),
|
||||
FunctionTemplate::New(isolate, Version));
|
||||
global_template->Set(
|
||||
Symbol::GetToStringTag(isolate),
|
||||
String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
|
||||
// Bind the Realm object.
|
||||
Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
|
||||
|
@ -2537,6 +2537,7 @@ MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
|
||||
if (is_array.FromJust()) {
|
||||
return isolate->factory()->Array_string();
|
||||
}
|
||||
|
||||
// TODO(adamk): According to ES2015, we should return "Function" when
|
||||
// object has a [[Call]] internal method (corresponds to IsCallable).
|
||||
// But this is well cemented in layout tests and might cause webbreakage.
|
||||
@ -2545,7 +2546,23 @@ MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
|
||||
// }
|
||||
// TODO(adamk): class_name() is expensive, replace with instance type
|
||||
// checks where possible.
|
||||
|
||||
InstanceType instance_type = object->map()->instance_type();
|
||||
switch (instance_type) {
|
||||
case JS_PROXY_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_API_OBJECT_TYPE:
|
||||
case JS_VALUE_TYPE:
|
||||
case JS_DATE_TYPE:
|
||||
// Arguments and Error objects have type JS_OBJECT_TYPE
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_REGEXP_TYPE:
|
||||
case JS_BOUND_FUNCTION_TYPE:
|
||||
case JS_FUNCTION_TYPE:
|
||||
return handle(object->class_name(), isolate);
|
||||
default:
|
||||
return isolate->factory()->Object_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -13351,7 +13351,7 @@ THREADED_TEST(ObjectProtoToString) {
|
||||
value =
|
||||
context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsString() &&
|
||||
value->Equals(context.local(), v8_str("[object global]")).FromJust());
|
||||
value->Equals(context.local(), v8_str("[object Object]")).FromJust());
|
||||
|
||||
// Check ordinary object
|
||||
Local<Value> object =
|
||||
@ -13397,7 +13397,7 @@ TEST(ObjectProtoToStringES6) {
|
||||
value =
|
||||
context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsString() &&
|
||||
value->Equals(context.local(), v8_str("[object global]")).FromJust());
|
||||
value->Equals(context.local(), v8_str("[object Object]")).FromJust());
|
||||
|
||||
// Check ordinary object
|
||||
Local<Value> object = CompileRun("new Object()");
|
||||
|
@ -15,9 +15,10 @@ var funs = {
|
||||
RegExp: [ RegExp ],
|
||||
Error: [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
|
||||
EvalError, URIError ]
|
||||
}
|
||||
for (f in funs) {
|
||||
for (i in funs[f]) {
|
||||
};
|
||||
for (var f in funs) {
|
||||
for (var i in funs[f]) {
|
||||
|
||||
assertEquals("[object " + f + "]",
|
||||
Object.prototype.toString.call(new funs[f][i]),
|
||||
funs[f][i]);
|
||||
@ -130,11 +131,11 @@ function testObjectToStringPropertyDesc() {
|
||||
}
|
||||
testObjectToStringPropertyDesc();
|
||||
|
||||
function testObjectToStringOwnNonStringValue() {
|
||||
var obj = Object.defineProperty({}, Symbol.toStringTag, { value: 1 });
|
||||
function testObjectToStringOnNonStringValue(obj) {
|
||||
Object.defineProperty(obj, Symbol.toStringTag, { value: 1 });
|
||||
assertEquals("[object Object]", ({}).toString.call(obj));
|
||||
}
|
||||
testObjectToStringOwnNonStringValue();
|
||||
testObjectToStringOnNonStringValue({});
|
||||
|
||||
|
||||
// Proxies
|
||||
@ -149,11 +150,64 @@ assertTag("Function", new Proxy(() => 42, {}));
|
||||
assertTag("Foo", new Proxy(() => 42, {get() {return "Foo"}}));
|
||||
assertTag("Function", new Proxy(() => 42, {get() {return 666}}));
|
||||
|
||||
revocable = Proxy.revocable([], {});
|
||||
var revocable = Proxy.revocable([], {});
|
||||
revocable.revoke();
|
||||
assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
|
||||
|
||||
handler = {};
|
||||
var handler = {};
|
||||
revocable = Proxy.revocable([], handler);
|
||||
handler.get = () => revocable.revoke();
|
||||
assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
|
||||
|
||||
function* gen() { yield 1; }
|
||||
|
||||
assertTag("GeneratorFunction", gen);
|
||||
Object.defineProperty(gen, Symbol.toStringTag, {writable: true});
|
||||
gen[Symbol.toStringTag] = "different string";
|
||||
assertTag("different string", gen);
|
||||
gen[Symbol.toStringTag] = 1;
|
||||
assertTag("Function", gen);
|
||||
|
||||
function overwriteToStringTagWithNonStringValue(tag, obj) {
|
||||
assertTag(tag, obj);
|
||||
|
||||
Object.defineProperty(obj, Symbol.toStringTag, {
|
||||
configurable: true,
|
||||
value: "different string"
|
||||
});
|
||||
assertTag("different string", obj);
|
||||
|
||||
testObjectToStringOnNonStringValue(obj);
|
||||
}
|
||||
|
||||
overwriteToStringTagWithNonStringValue("global", global);
|
||||
overwriteToStringTagWithNonStringValue("Generator", gen());
|
||||
|
||||
var arrayBuffer = new ArrayBuffer();
|
||||
overwriteToStringTagWithNonStringValue("ArrayBuffer", arrayBuffer);
|
||||
overwriteToStringTagWithNonStringValue("DataView", new DataView(arrayBuffer));
|
||||
|
||||
overwriteToStringTagWithNonStringValue("Int8Array", new Int8Array());
|
||||
overwriteToStringTagWithNonStringValue("Uint8Array", new Uint8Array());
|
||||
overwriteToStringTagWithNonStringValue("Uint8ClampedArray",
|
||||
new Uint8ClampedArray());
|
||||
overwriteToStringTagWithNonStringValue("Int16Array", new Int16Array());
|
||||
overwriteToStringTagWithNonStringValue("Uint16Array", new Uint16Array());
|
||||
overwriteToStringTagWithNonStringValue("Int32Array", new Int32Array());
|
||||
overwriteToStringTagWithNonStringValue("Uint32Array", new Uint32Array());
|
||||
overwriteToStringTagWithNonStringValue("Float32Array", new Float32Array());
|
||||
overwriteToStringTagWithNonStringValue("Float64Array", new Float64Array());
|
||||
|
||||
var set = new Set();
|
||||
var map = new Map();
|
||||
|
||||
overwriteToStringTagWithNonStringValue("Set", set);
|
||||
overwriteToStringTagWithNonStringValue("Map", map);
|
||||
|
||||
overwriteToStringTagWithNonStringValue("Set Iterator", set[Symbol.iterator]());
|
||||
overwriteToStringTagWithNonStringValue("Map Iterator", map[Symbol.iterator]());
|
||||
|
||||
overwriteToStringTagWithNonStringValue("WeakSet", new WeakSet());
|
||||
overwriteToStringTagWithNonStringValue("WeakMap", new WeakMap());
|
||||
|
||||
overwriteToStringTagWithNonStringValue("Promise", new Promise(function() {}));
|
||||
|
Loading…
Reference in New Issue
Block a user