Commit 263dce9b authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[js] Remove CORE JS Natives (prologue.js), port extra utils to C++/Torque

- Removes the last `CORE` JS native script: `prologue.js`.
- Removes build step and bootstrapping associated with building/loading `CORE` JS natives.
- Removes `natives_utils_object` from context.
- Deprecates `--expose-natives-as` flag.
- Ports extra utils functions to C++ (`uncurryThis`) or Torque
  (`createPrivateSymbol`, `markPromiseAsHandled`, and `promiseState`).
- Move extra utils constants initialization into bootstrapper
  (`kPROMISE_PENDING`, `kPROMISE_FULFILLED`, `kPROMISE_REJECTED`).
- Removes unused extra utils functions `log` and `logStackTrace`.

Drive-by: Added test coverage for Array#includes being an unscopeable.

Bug: v8:7624
Change-Id: I5d983f8d11b76cb4dd3c2c67592ce1dc88364cd9
Reviewed-on: https://chromium-review.googlesource.com/c/1381672Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Cr-Commit-Position: refs/heads/master@{#58577}
parent 2a9a60a5
......@@ -711,36 +711,6 @@ template("asm_to_inline_asm") {
}
}
action("js2c") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
script = "tools/js2c.py"
# NOSORT
sources = [
"src/js/macros.py",
"src/message-template.h",
"src/js/prologue.js",
]
outputs = [
"$target_gen_dir/libraries.cc",
]
args = [
rebase_path("$target_gen_dir/libraries.cc", root_build_dir),
"CORE",
] + rebase_path(sources, root_build_dir)
if (v8_use_external_startup_data) {
outputs += [ "$target_gen_dir/libraries.bin" ]
args += [
"--startup_blob",
rebase_path("$target_gen_dir/libraries.bin", root_build_dir),
]
}
}
action("js2c_extras") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
......@@ -840,14 +810,12 @@ if (v8_use_external_startup_data) {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":js2c",
":js2c_experimental_extras",
":js2c_extras",
]
# NOSORT
sources = [
"$target_gen_dir/libraries.bin",
"$target_gen_dir/libraries_extras.bin",
"$target_gen_dir/libraries_experimental_extras.bin",
]
......@@ -950,6 +918,7 @@ torque_files = [
"src/builtins/array-unshift.tq",
"src/builtins/collections.tq",
"src/builtins/data-view.tq",
"src/builtins/extras-utils.tq",
"src/builtins/object.tq",
"src/builtins/object-fromentries.tq",
"src/builtins/iterator.tq",
......@@ -967,6 +936,7 @@ torque_namespaces = [
"object",
"typed-array",
"data-view",
"extras-utils",
"test",
]
......@@ -1252,7 +1222,6 @@ v8_source_set("v8_nosnapshot") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":js2c",
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
......@@ -1261,7 +1230,6 @@ v8_source_set("v8_nosnapshot") {
sources = [
"$target_gen_dir/experimental-extras-libraries.cc",
"$target_gen_dir/extras-libraries.cc",
"$target_gen_dir/libraries.cc",
"src/snapshot/embedded-empty.cc",
"src/snapshot/snapshot-empty.cc",
]
......@@ -1271,7 +1239,6 @@ v8_source_set("v8_nosnapshot") {
# TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
# Generated source, contains same variable names as libraries.cc
"$target_gen_dir/experimental-extras-libraries.cc",
"$target_gen_dir/libraries.cc",
]
}
......@@ -1288,7 +1255,6 @@ if (v8_use_snapshot && !v8_use_external_startup_data) {
]
deps = [
":js2c",
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
......@@ -1305,7 +1271,6 @@ if (v8_use_snapshot && !v8_use_external_startup_data) {
sources = [
"$target_gen_dir/experimental-extras-libraries.cc",
"$target_gen_dir/extras-libraries.cc",
"$target_gen_dir/libraries.cc",
"$target_gen_dir/snapshot.cc",
"src/setup-isolate-deserialize.cc",
]
......@@ -1324,7 +1289,6 @@ if (v8_use_snapshot && !v8_use_external_startup_data) {
# TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
# Generated source, contains same variable names as libraries.cc
"$target_gen_dir/experimental-extras-libraries.cc",
"$target_gen_dir/libraries.cc",
]
}
......@@ -1337,7 +1301,6 @@ if (v8_use_snapshot && v8_use_external_startup_data) {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":js2c",
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
......@@ -1700,6 +1663,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-definitions.h",
"src/builtins/builtins-descriptors.h",
"src/builtins/builtins-error.cc",
"src/builtins/builtins-extras-utils.cc",
"src/builtins/builtins-function.cc",
"src/builtins/builtins-global.cc",
"src/builtins/builtins-internal.cc",
......@@ -4182,7 +4146,6 @@ group("v8_generated_cc_files") {
deps = [
":d8_js2c",
":generate_bytecode_builtins_list",
":js2c",
":js2c_experimental_extras",
":js2c_extras",
":run_torque",
......
This diff is collapsed.
......@@ -91,12 +91,9 @@ class Bootstrapper final {
static bool CompileNative(Isolate* isolate, Vector<const char> name,
Handle<String> source, int argc,
Handle<Object> argv[], NativesFlag natives_flag);
static bool CompileBuiltin(Isolate* isolate, int index);
static bool CompileExtraBuiltin(Isolate* isolate, int index);
static bool CompileExperimentalExtraBuiltin(Isolate* isolate, int index);
static void ExportFromRuntime(Isolate* isolate, Handle<JSObject> container);
private:
// Log newly created Map objects if no snapshot was used.
void LogAllMaps();
......
......@@ -602,6 +602,10 @@ namespace internal {
CPP(MakeTypeError) \
CPP(MakeURIError) \
\
/* ExtrasUtils */ \
CPP(ExtrasUtilsUncurryThis) \
CPP(ExtrasUtilsCallReflectApply) \
\
/* Function */ \
CPP(FunctionConstructor) \
ASM(FunctionPrototypeApply, Dummy) \
......
// 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.
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/elements.h"
#include "src/counters.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace {
enum UncurryThisFunctionContextSlot {
kFunctionSlot = Context::MIN_CONTEXT_SLOTS,
kFunctionContextLength,
};
} // namespace
// These functions are key for safe meta-programming:
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
//
// Technically they could all be derived from combinations of
// Function.prototype.{bind,call,apply} but that introduces lots of layers of
// indirection.
//
// Equivalent to:
//
// function uncurryThis(func) {
// return function(thisArg, ...args) {
// return %reflect_apply(func, thisArg, args);
// };
// };
//
BUILTIN(ExtrasUtilsUncurryThis) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<JSFunction> function = args.at<JSFunction>(1);
Handle<NativeContext> native_context(isolate->context()->native_context(),
isolate);
Handle<Context> context = isolate->factory()->NewBuiltinContext(
native_context,
static_cast<int>(UncurryThisFunctionContextSlot::kFunctionContextLength));
context->set(static_cast<int>(UncurryThisFunctionContextSlot::kFunctionSlot),
*function);
Handle<SharedFunctionInfo> info =
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->empty_string(),
Builtins::kExtrasUtilsCallReflectApply, kNormalFunction);
info->DontAdaptArguments();
Handle<Map> map = isolate->strict_function_without_prototype_map();
Handle<JSFunction> new_bound_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
return *new_bound_function;
}
BUILTIN(ExtrasUtilsCallReflectApply) {
HandleScope scope(isolate);
Handle<Context> context(isolate->context(), isolate);
Handle<NativeContext> native_context(isolate->context()->native_context(),
isolate);
Handle<JSFunction> function(
JSFunction::cast(context->get(
static_cast<int>(UncurryThisFunctionContextSlot::kFunctionSlot))),
isolate);
Handle<Object> this_arg = args.at(1);
int const rest_args_atart = 2;
Arguments argv(args.length() - rest_args_atart,
args.address_of_arg_at(rest_args_atart));
Handle<JSArray> rest_args_array = isolate->factory()->NewJSArray(0);
RETURN_FAILURE_ON_EXCEPTION(
isolate, ArrayConstructInitializeElements(rest_args_array, &argv));
Handle<Object> reflect_apply_args[] = {function, this_arg, rest_args_array};
Handle<JSFunction> reflect_apply(native_context->reflect_apply(), isolate);
RETURN_RESULT_OR_FAILURE(
isolate,
Execution::Call(isolate, reflect_apply,
isolate->factory()->undefined_value(),
arraysize(reflect_apply_args), reflect_apply_args));
}
} // namespace internal
} // namespace v8
// Copyright 2018 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.
namespace extras_utils {
extern runtime CreatePrivateSymbol(Context, Object): HeapObject;
extern runtime PromiseMarkAsHandled(Context, Object): Undefined;
extern runtime PromiseStatus(Context, Object): Smi;
javascript builtin ExtrasUtilsCreatePrivateSymbol(
context: Context, receiver: Object, ...arguments): HeapObject {
return CreatePrivateSymbol(context, arguments[0]);
}
javascript builtin ExtrasUtilsMarkPromiseAsHandled(
context: Context, receiver: Object, ...arguments): Undefined {
return PromiseMarkAsHandled(context, arguments[0]);
}
javascript builtin ExtrasUtilsPromiseState(
context: Context, receiver: Object, ...arguments): Smi {
return PromiseStatus(context, arguments[0]);
}
}
......@@ -205,7 +205,6 @@ enum ContextLookupFlags {
V(MATH_RANDOM_STATE_INDEX, ByteArray, math_random_state) \
V(MATH_RANDOM_CACHE_INDEX, FixedDoubleArray, math_random_cache) \
V(MESSAGE_LISTENERS_INDEX, TemplateList, message_listeners) \
V(NATIVES_UTILS_OBJECT_INDEX, Object, natives_utils_object) \
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
......
......@@ -873,7 +873,6 @@ DEFINE_BOOL(disable_old_api_accessors, false,
"prototype chain")
// bootstrapper.cc
DEFINE_STRING(expose_natives_as, nullptr, "expose natives in global object")
DEFINE_BOOL(expose_free_buffer, false, "expose freeBuffer extension")
DEFINE_BOOL(expose_gc, false, "expose gc extension")
DEFINE_STRING(expose_gc_as, nullptr,
......
// Copyright 2015 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.
(function(global, utils, extrasUtils) {
"use strict";
%CheckIsBootstrapping();
// -----------------------------------------------------------------------
// Utils
var imports = UNDEFINED;
var exports_container = %ExportFromRuntime({});
// Export to other scripts.
function Export(f) {
f(exports_container);
}
// Import from other scripts. The actual importing happens in PostNatives so
// that we can import from scripts executed later. However, that means that
// the import is not available until the very end.
function Import(f) {
f.next = imports;
imports = f;
}
// -----------------------------------------------------------------------
// To be called by bootstrapper
function PostNatives(utils) {
%CheckIsBootstrapping();
for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
imports(exports_container);
}
exports_container = UNDEFINED;
utils.Export = UNDEFINED;
utils.Import = UNDEFINED;
utils.PostNatives = UNDEFINED;
}
// -----------------------------------------------------------------------
%OptimizeObjectForAddingMultipleProperties(utils, 14);
utils.Import = Import;
utils.Export = Export;
utils.PostNatives = PostNatives;
%ToFastProperties(utils);
// -----------------------------------------------------------------------
%OptimizeObjectForAddingMultipleProperties(extrasUtils, 11);
extrasUtils.logStackTrace = function logStackTrace() {
%DebugTrace();
};
extrasUtils.log = function log() {
let message = '';
for (const arg of arguments) {
message += arg;
}
%GlobalPrint(message);
};
// Extras need the ability to store private state on their objects without
// exposing it to the outside world.
extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) {
return %CreatePrivateSymbol(name);
};
// These functions are key for safe meta-programming:
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
//
// Technically they could all be derived from combinations of
// Function.prototype.{bind,call,apply} but that introduces lots of layers of
// indirection.
extrasUtils.uncurryThis = function uncurryThis(func) {
return function(thisArg, ...args) {
return %reflect_apply(func, thisArg, args);
};
};
extrasUtils.markPromiseAsHandled = function markPromiseAsHandled(promise) {
%PromiseMarkAsHandled(promise);
};
extrasUtils.promiseState = function promiseState(promise) {
return %PromiseStatus(promise);
};
// [[PromiseState]] values (for extrasUtils.promiseState())
// These values should be kept in sync with PromiseStatus in globals.h
extrasUtils.kPROMISE_PENDING = 0;
extrasUtils.kPROMISE_FULFILLED = 1;
extrasUtils.kPROMISE_REJECTED = 2;
%ToFastProperties(extrasUtils);
})
......@@ -32,18 +32,6 @@ RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_ExportFromRuntime) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, container, 0);
CHECK(isolate->bootstrapper()->IsActive());
JSObject::NormalizeProperties(container, KEEP_INOBJECT_PROPERTIES, 10,
"ExportFromRuntime");
Bootstrapper::ExportFromRuntime(isolate, container);
JSObject::MigrateSlowToFast(container, 0, "ExportFromRuntime");
return *container;
}
RUNTIME_FUNCTION(Runtime_Throw) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -216,7 +216,6 @@ namespace internal {
I(CreateAsyncFromSyncIterator, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \
F(CreateTemplateObject, 1, 1) \
F(ExportFromRuntime, 1, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(IncrementUseCounter, 1, 1) \
F(Interrupt, 0, 1) \
......
......@@ -17,10 +17,6 @@ NativesExternalStringResource::NativesExternalStringResource(NativeType type,
Vector<const char> source;
DCHECK_LE(0, index);
switch (type_) {
case CORE:
DCHECK(index < Natives::GetBuiltinsCount());
source = Natives::GetScriptSource(index);
break;
case EXTRAS:
DCHECK(index < ExtraNatives::GetBuiltinsCount());
source = ExtraNatives::GetScriptSource(index);
......
......@@ -133,9 +133,8 @@ static StartupData* natives_blob_ = nullptr;
* Read the Natives blob, as previously set by SetNativesFromFile.
*/
void ReadNatives() {
if (natives_blob_ && NativesHolder<CORE>::empty()) {
if (natives_blob_ && NativesHolder<EXTRAS>::empty()) {
SnapshotByteSource bytes(natives_blob_->data, natives_blob_->raw_size);
NativesHolder<CORE>::set(NativesStore::MakeFromScriptsSource(&bytes));
NativesHolder<EXTRAS>::set(NativesStore::MakeFromScriptsSource(&bytes));
NativesHolder<EXPERIMENTAL_EXTRAS>::set(
NativesStore::MakeFromScriptsSource(&bytes));
......@@ -163,7 +162,6 @@ void SetNativesFromFile(StartupData* natives_blob) {
* Release memory allocated by SetNativesFromFile.
*/
void DisposeNatives() {
NativesHolder<CORE>::Dispose();
NativesHolder<EXTRAS>::Dispose();
NativesHolder<EXPERIMENTAL_EXTRAS>::Dispose();
}
......@@ -208,7 +206,6 @@ Vector<const char> NativesCollection<type>::GetScriptsSource() {
template Vector<const char> NativesCollection<T>::GetScriptSource(int i); \
template Vector<const char> NativesCollection<T>::GetScriptName(int i); \
template Vector<const char> NativesCollection<T>::GetScriptsSource();
INSTANTIATE_TEMPLATES(CORE)
INSTANTIATE_TEMPLATES(EXTRAS)
INSTANTIATE_TEMPLATES(EXPERIMENTAL_EXTRAS)
#undef INSTANTIATE_TEMPLATES
......
......@@ -15,7 +15,6 @@ namespace v8 {
namespace internal {
enum NativeType {
CORE,
EXTRAS,
EXPERIMENTAL_EXTRAS,
D8,
......@@ -42,7 +41,6 @@ class V8_EXPORT_PRIVATE NativesCollection {
static Vector<const char> GetScriptsSource();
};
typedef NativesCollection<CORE> Natives;
typedef NativesCollection<EXTRAS> ExtraNatives;
typedef NativesCollection<EXPERIMENTAL_EXTRAS> ExperimentalExtraNatives;
......@@ -63,8 +61,8 @@ class NativesExternalStringResource final
size_t length() const override { return length_; }
v8::String::ExternalOneByteStringResource* EncodeForSerialization() const {
DCHECK(type_ == CORE || type_ == EXTRAS);
intptr_t val = (index_ << 1) | ((type_ == CORE) ? 0 : 1);
DCHECK(type_ == EXTRAS);
intptr_t val = (index_ << 1) | 1;
val = val << kPointerSizeLog2; // Pointer align.
return reinterpret_cast<v8::String::ExternalOneByteStringResource*>(val);
}
......@@ -73,9 +71,9 @@ class NativesExternalStringResource final
static NativesExternalStringResource* DecodeForDeserialization(
const v8::String::ExternalOneByteStringResource* encoded) {
intptr_t val = reinterpret_cast<intptr_t>(encoded) >> kPointerSizeLog2;
NativeType type = (val & 1) ? EXTRAS : CORE;
DCHECK(val & 1);
int index = static_cast<int>(val >> 1);
return new NativesExternalStringResource(type, index);
return new NativesExternalStringResource(EXTRAS, index);
}
private:
......
......@@ -4980,49 +4980,6 @@ TEST(PreprocessStackTrace) {
}
static bool utils_has_been_collected = false;
static void UtilsHasBeenCollected(
const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
utils_has_been_collected = true;
data.GetParameter()->Reset();
}
TEST(BootstrappingExports) {
// Expose utils object and delete it to observe that it is indeed
// being garbage-collected.
FLAG_expose_natives_as = "utils";
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
LocalContext env;
if (Snapshot::HasContextSnapshot(CcTest::i_isolate(), 0)) return;
utils_has_been_collected = false;
v8::Persistent<v8::Object> utils;
{
v8::HandleScope scope(isolate);
v8::Local<v8::String> name = v8_str("utils");
utils.Reset(isolate, CcTest::global()
->Get(env.local(), name)
.ToLocalChecked()
->ToObject(env.local())
.ToLocalChecked());
CHECK(CcTest::global()->Delete(env.local(), name).FromJust());
}
utils.SetWeak(&utils, UtilsHasBeenCollected,
v8::WeakCallbackType::kParameter);
CcTest::CollectAllAvailableGarbage();
CHECK(utils_has_been_collected);
}
void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) {
CHECK_LE(FixedArray::kHeaderSize, bytes);
CHECK(IsAligned(bytes, kTaggedSize));
......
......@@ -26750,6 +26750,11 @@ TEST(ExtrasUtilsObject) {
.ToLocalChecked()
.As<v8::Boolean>();
CHECK_EQ(false, thenable_is_promise->Value());
auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
.ToLocalChecked()
.As<v8::Boolean>();
CHECK_EQ(true, uncurry_this->Value());
}
......
......@@ -4269,7 +4269,6 @@ i::MaybeHandle<i::Script> FindScript(
UNINITIALIZED_TEST(LoadedAtStartupScripts) {
i::FLAG_expose_gc = true;
i::FLAG_expose_natives_as = "natives";
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
......@@ -4296,17 +4295,12 @@ UNINITIALIZED_TEST(LoadedAtStartupScripts) {
scripts.emplace_back(script, i_isolate);
}
}
CHECK_EQ(count_by_type[i::Script::TYPE_NATIVE],
i::Natives::GetBuiltinsCount());
CHECK_EQ(count_by_type[i::Script::TYPE_NATIVE], 0);
CHECK_EQ(count_by_type[i::Script::TYPE_EXTENSION], 2);
CHECK_EQ(count_by_type[i::Script::TYPE_NORMAL], 1);
CHECK_EQ(count_by_type[i::Script::TYPE_WASM], 0);
CHECK_EQ(count_by_type[i::Script::TYPE_INSPECTOR], 0);
i::Handle<i::Script> native_prologue_script =
FindScript(i_isolate, scripts, "native prologue.js").ToHandleChecked();
CHECK_EQ(native_prologue_script->type(), i::Script::TYPE_NATIVE);
i::Handle<i::Script> gc_script =
FindScript(i_isolate, scripts, "v8/gc").ToHandleChecked();
CHECK_EQ(gc_script->type(), i::Script::TYPE_EXTENSION);
......
......@@ -103,6 +103,10 @@
promiseStateToString(fulfilledPromise) + ' ' +
promiseStateToString(rejectedPromise);
const uncurryThis = v8.uncurryThis(function (a, b, c, d, e) {
return (this + a + b + c + d + e) === 21;
})(1, 2, 3, 4, 5, 6);
return {
privateSymbol: v8.createPrivateSymbol('sym'),
fulfilledPromise, // should be fulfilled with 1
......@@ -111,7 +115,8 @@
rejectedButHandledPromise, // should be rejected but have a handler
promiseStates, // should be the string "pending fulfilled rejected"
promiseIsPromise: v8.isPromise(fulfilledPromise), // should be true
thenableIsPromise: v8.isPromise({ then() { } }) // should be false
thenableIsPromise: v8.isPromise({ then() { } }), // should be false
uncurryThis // should be true
};
};
})
......@@ -188,7 +188,7 @@ TEST(FlagsRemoveIncomplete) {
// if the list of arguments ends unexpectedly.
SetFlagsToDefault();
int argc = 3;
const char* argv[] = {"", "--testing-bool-flag", "--expose-natives-as"};
const char* argv[] = {"", "--testing-bool-flag", "--expose-gc-as"};
CHECK_EQ(2, FlagList::SetFlagsFromCommandLine(&argc,
const_cast<char **>(argv),
true));
......
......@@ -99,6 +99,7 @@ function TestArrayPrototypeUnscopables() {
var flat = 'local flat';
var flatMap = 'local flatMap';
var keys = 'local keys';
var includes = 'local includes';
var values = 'local values';
var array = [];
......@@ -112,6 +113,7 @@ function TestArrayPrototypeUnscopables() {
assertEquals('local findIndex', findIndex);
assertEquals('local flat', flat);
assertEquals('local flatMap', flatMap);
assertEquals('local includes', includes);
assertEquals('local keys', keys);
assertEquals('local values', values);
assertEquals(42, toString);
......
// 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: --expose-natives-as 1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment