diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 4d042ea3c6..90f1c6701b 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1148,6 +1148,19 @@ void Genesis::InitializeGlobal(Handle global_object, SimpleInstallFunction(prototype, factory->toString_string(), Builtins::kFunctionPrototypeToString, 0, false); + // Install the @@hasInstance function. + Handle has_instance = InstallFunction( + prototype, factory->has_instance_symbol(), JS_OBJECT_TYPE, + JSObject::kHeaderSize, MaybeHandle(), + Builtins::kFunctionHasInstance, + static_cast(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 name = factory->Proxy_string(); Handle code(isolate->builtins()->ProxyConstructor()); - Handle proxy_function = factory->NewFunction( - isolate->proxy_function_map(), factory->Proxy_string(), code); + Handle proxy_function = + factory->NewFunction(isolate->proxy_function_map(), + factory->Proxy_string(), MaybeHandle(code)); JSFunction::SetInitialMap(proxy_function, Handle(native_context()->proxy_map(), isolate), diff --git a/src/builtins.cc b/src/builtins.cc index 7cc65cdabb..3aef9abb15 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -3467,6 +3467,45 @@ BUILTIN(GeneratorFunctionConstructor) { return *result; } +// ES6 section 19.2.3.6 Function.prototype[@@hasInstance](V) +BUILTIN(FunctionHasInstance) { + HandleScope scope(isolate); + Handle callable = args.receiver(); + Handle 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::cast(callable)->bound_target_function(), + isolate); + } + DCHECK(callable->IsCallable()); + // Get the "prototype" of {callable}; raise an error if it's not a receiver. + Handle 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 receiver = Handle::cast(object); + Maybe 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) { diff --git a/src/builtins.h b/src/builtins.h index 2015d48ac9..4d8fb455e0 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -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) \ \ diff --git a/src/heap-symbols.h b/src/heap-symbols.h index 62e56e2085..253a8dd13c 100644 --- a/src/heap-symbols.h +++ b/src/heap-symbols.h @@ -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) diff --git a/src/js/symbol.js b/src/js/symbol.js index 0c87a117ee..ae543691c2 100644 --- a/src/js/symbol.js +++ b/src/js/symbol.js @@ -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. diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 036643b2f4..99716bd850 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -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], diff --git a/test/mjsunit/es6/hasinstance-symbol.js b/test/mjsunit/es6/hasinstance-symbol.js new file mode 100644 index 0000000000..6783d8deef --- /dev/null +++ b/test/mjsunit/es6/hasinstance-symbol.js @@ -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()); +})(); diff --git a/test/mjsunit/es6/symbols.js b/test/mjsunit/es6/symbols.js index d502a83681..38338575a0 100644 --- a/test/mjsunit/es6/symbols.js +++ b/test/mjsunit/es6/symbols.js @@ -441,8 +441,9 @@ TestGetOwnPropertySymbolsWithProto() function TestWellKnown() { var symbols = [ + "hasInstance", // TODO(rossberg): reactivate once implemented. - // "hasInstance", "isConcatSpreadable", "isRegExp", + // "isConcatSpreadable", "isRegExp", "iterator", /* "toStringTag", */ "unscopables" ] diff --git a/test/test262/test262.status b/test/test262/test262.status index 3823ee7a3e..8bd8c42019 100644 --- a/test/test262/test262.status +++ b/test/test262/test262.status @@ -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],