Implement symbol @@hasInstance for ES6 instanceof support.
BUG= Review URL: https://codereview.chromium.org/1683043003 Cr-Commit-Position: refs/heads/master@{#33870}
This commit is contained in:
parent
24b40f35f4
commit
5833e8e8a4
@ -1148,6 +1148,19 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
SimpleInstallFunction(prototype, factory->toString_string(),
|
||||
Builtins::kFunctionPrototypeToString, 0, false);
|
||||
|
||||
// Install the @@hasInstance function.
|
||||
Handle<JSFunction> has_instance = InstallFunction(
|
||||
prototype, factory->has_instance_symbol(), JS_OBJECT_TYPE,
|
||||
JSObject::kHeaderSize, MaybeHandle<JSObject>(),
|
||||
Builtins::kFunctionHasInstance,
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY));
|
||||
|
||||
// Set the expected parameters for @@hasInstance to 1; required by builtin.
|
||||
has_instance->shared()->set_internal_formal_parameter_count(1);
|
||||
|
||||
// Set the length for the function to satisfy ECMA-262.
|
||||
has_instance->shared()->set_length(1);
|
||||
|
||||
// Install the "constructor" property on the %FunctionPrototype%.
|
||||
JSObject::AddProperty(prototype, factory->constructor_string(),
|
||||
function_fun, DONT_ENUM);
|
||||
@ -2515,8 +2528,9 @@ void Genesis::InitializeGlobal_harmony_proxies() {
|
||||
Handle<String> name = factory->Proxy_string();
|
||||
Handle<Code> code(isolate->builtins()->ProxyConstructor());
|
||||
|
||||
Handle<JSFunction> proxy_function = factory->NewFunction(
|
||||
isolate->proxy_function_map(), factory->Proxy_string(), code);
|
||||
Handle<JSFunction> proxy_function =
|
||||
factory->NewFunction(isolate->proxy_function_map(),
|
||||
factory->Proxy_string(), MaybeHandle<Code>(code));
|
||||
|
||||
JSFunction::SetInitialMap(proxy_function,
|
||||
Handle<Map>(native_context()->proxy_map(), isolate),
|
||||
|
@ -3467,6 +3467,45 @@ BUILTIN(GeneratorFunctionConstructor) {
|
||||
return *result;
|
||||
}
|
||||
|
||||
// ES6 section 19.2.3.6 Function.prototype[@@hasInstance](V)
|
||||
BUILTIN(FunctionHasInstance) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> callable = args.receiver();
|
||||
Handle<Object> object = args.atOrUndefined(isolate, 1);
|
||||
|
||||
// {callable} must have a [[Call]] internal method.
|
||||
if (!callable->IsCallable()) {
|
||||
return isolate->heap()->false_value();
|
||||
}
|
||||
// If {object} is not a receiver, return false.
|
||||
if (!object->IsJSReceiver()) {
|
||||
return isolate->heap()->false_value();
|
||||
}
|
||||
// Check if {callable} is bound, if so, get [[BoundTargetFunction]] from it
|
||||
// and use that instead of {callable}.
|
||||
while (callable->IsJSBoundFunction()) {
|
||||
callable =
|
||||
handle(Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
|
||||
isolate);
|
||||
}
|
||||
DCHECK(callable->IsCallable());
|
||||
// Get the "prototype" of {callable}; raise an error if it's not a receiver.
|
||||
Handle<Object> prototype;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, prototype,
|
||||
Object::GetProperty(callable, isolate->factory()->prototype_string()));
|
||||
if (!prototype->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype));
|
||||
}
|
||||
// Return whether or not {prototype} is in the prototype chain of {object}.
|
||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
|
||||
Maybe<bool> result =
|
||||
JSReceiver::HasInPrototypeChain(isolate, receiver, prototype);
|
||||
MAYBE_RETURN(result, isolate->heap()->exception());
|
||||
return isolate->heap()->ToBoolean(result.FromJust());
|
||||
}
|
||||
|
||||
// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case.
|
||||
BUILTIN(SymbolConstructor) {
|
||||
|
@ -102,6 +102,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
|
||||
V(FunctionConstructor, kTargetAndNewTarget) \
|
||||
V(FunctionPrototypeBind, kNone) \
|
||||
V(FunctionPrototypeToString, kNone) \
|
||||
V(FunctionHasInstance, kNone) \
|
||||
\
|
||||
V(GeneratorFunctionConstructor, kTargetAndNewTarget) \
|
||||
\
|
||||
|
@ -181,7 +181,6 @@
|
||||
V(uninitialized_symbol)
|
||||
|
||||
#define PUBLIC_SYMBOL_LIST(V) \
|
||||
V(has_instance_symbol, Symbol.hasInstance) \
|
||||
V(iterator_symbol, Symbol.iterator) \
|
||||
V(match_symbol, Symbol.match) \
|
||||
V(replace_symbol, Symbol.replace) \
|
||||
@ -196,6 +195,7 @@
|
||||
// check. Because this behaviour is not specified properly as of yet, it only
|
||||
// applies to a subset of spec-defined Well-Known Symbols.
|
||||
#define WELL_KNOWN_SYMBOL_LIST(V) \
|
||||
V(has_instance_symbol, Symbol.hasInstance) \
|
||||
V(is_concat_spreadable_symbol, Symbol.isConcatSpreadable) \
|
||||
V(to_string_tag_symbol, Symbol.toStringTag)
|
||||
|
||||
|
@ -75,8 +75,7 @@ function SymbolKeyFor(symbol) {
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
utils.InstallConstants(GlobalSymbol, [
|
||||
// TODO(rossberg): expose when implemented.
|
||||
// "hasInstance", hasInstanceSymbol,
|
||||
"hasInstance", hasInstanceSymbol,
|
||||
"isConcatSpreadable", isConcatSpreadableSymbol,
|
||||
"iterator", iteratorSymbol,
|
||||
// TODO(yangguo): expose when implemented.
|
||||
|
@ -695,6 +695,7 @@
|
||||
'test-serialize/SerializeInternalReference': [PASS, FAIL],
|
||||
'test-spaces/SizeOfFirstPageIsLargeEnough': [PASS, FAIL],
|
||||
'test-api/InitializeDefaultIsolateOnSecondaryThread1': [PASS, FAIL],
|
||||
'test-api/FastReturnValuesWithProfiler': [PASS, FAIL],
|
||||
'test-heap/Regress538257': [PASS, FAIL],
|
||||
'test-heap/AddInstructionChangesNewSpacePromotion': [PASS, FAIL],
|
||||
'test-decls/CrossScriptReferencesHarmony': [PASS, FAIL],
|
||||
|
12
test/mjsunit/es6/hasinstance-symbol.js
Normal file
12
test/mjsunit/es6/hasinstance-symbol.js
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Verify that the hasInstance symbol is installed on function prototype.
|
||||
// Test262 makes deeper tests.
|
||||
|
||||
(function TestHasInstance() {
|
||||
var a = Array();
|
||||
assertTrue(Array[Symbol.hasInstance](a));
|
||||
assertFalse(Function.prototype[Symbol.hasInstance].call());
|
||||
})();
|
@ -441,8 +441,9 @@ TestGetOwnPropertySymbolsWithProto()
|
||||
|
||||
function TestWellKnown() {
|
||||
var symbols = [
|
||||
"hasInstance",
|
||||
// TODO(rossberg): reactivate once implemented.
|
||||
// "hasInstance", "isConcatSpreadable", "isRegExp",
|
||||
// "isConcatSpreadable", "isRegExp",
|
||||
"iterator", /* "toStringTag", */ "unscopables"
|
||||
]
|
||||
|
||||
|
@ -256,8 +256,6 @@
|
||||
'intl402/Collator/10.1.1_a': [FAIL],
|
||||
|
||||
# https://code.google.com/p/v8/issues/detail?id=4447
|
||||
'built-ins/Function/prototype/Symbol.hasInstance/*': [SKIP],
|
||||
'built-ins/Symbol/hasInstance/prop-desc': [FAIL],
|
||||
'language/expressions/instanceof/prototype-getter-with-object-throws': [FAIL],
|
||||
'language/expressions/instanceof/prototype-getter-with-object': [FAIL],
|
||||
'language/expressions/instanceof/primitive-prototype-with-object': [FAIL],
|
||||
|
Loading…
Reference in New Issue
Block a user