deps: V8: backport 74571c8

Original commit message:

    Fix preview of set entries

    Set entries return an array with the value as first and second entry.
    As such these are considered key value pairs to align with maps
    entries iterator.
    So far the return value was identical to the values iterator and that
    is misleading.

    This also adds tests to verify the results and improves the coverage
    a tiny bit by testing different iterators.

    Refs: https://github.com/nodejs/node/issues/24629

    R=yangguo@chromium.org

    Change-Id: I669a724bb4afaf5a713e468b1f51691d22c25253
    Reviewed-on: https://chromium-review.googlesource.com/c/1350790
    Commit-Queue: Yang Guo <yangguo@chromium.org>
    Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
    Reviewed-by: Jakob Gruber <jgruber@chromium.org>
    Reviewed-by: Yang Guo <yangguo@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#59311}

Refs: 74571c80a9

PR-URL: https://github.com/nodejs/node/pull/25941
Fixes: https://github.com/nodejs/node/issues/24629
Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
Ruben Bridgewater 2019-02-04 21:13:20 +01:00
parent 14c089b50e
commit e557647470
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
7 changed files with 280 additions and 31 deletions

View File

@ -37,7 +37,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.13',
'v8_embedder_string': '-node.14',
##### V8 defaults for Node.js #####

1
deps/v8/AUTHORS vendored
View File

@ -143,6 +143,7 @@ Rick Waldron <waldron.rick@gmail.com>
Rob Wu <rob@robwu.nl>
Robert Mustacchi <rm@fingolfin.org>
Robert Nagy <robert.nagy@gmail.com>
Ruben Bridgewater <ruben@bridgewater.de>
Ryan Dahl <ry@tinyclouds.org>
Sakthipriyan Vairamani (thefourtheye) <thechargingvolcano@gmail.com>
Sander Mathijs van Veen <sander@leaningtech.com>

31
deps/v8/src/api.cc vendored
View File

@ -7028,6 +7028,11 @@ enum class MapAsArrayKind {
kValues = i::JS_MAP_VALUE_ITERATOR_TYPE
};
enum class SetAsArrayKind {
kEntries = i::JS_SET_KEY_VALUE_ITERATOR_TYPE,
kValues = i::JS_SET_VALUE_ITERATOR_TYPE
};
i::Handle<i::JSArray> MapAsArray(i::Isolate* isolate, i::Object* table_obj,
int offset, MapAsArrayKind kind) {
i::Factory* factory = isolate->factory();
@ -7137,13 +7142,14 @@ Maybe<bool> Set::Delete(Local<Context> context, Local<Value> key) {
namespace {
i::Handle<i::JSArray> SetAsArray(i::Isolate* isolate, i::Object* table_obj,
int offset) {
int offset, SetAsArrayKind kind) {
i::Factory* factory = isolate->factory();
i::Handle<i::OrderedHashSet> table(i::OrderedHashSet::cast(table_obj),
isolate);
// Elements skipped by |offset| may already be deleted.
int capacity = table->UsedCapacity();
int max_length = capacity - offset;
const bool collect_key_values = kind == SetAsArrayKind::kEntries;
int max_length = (capacity - offset) * (collect_key_values ? 2 : 1);
if (max_length == 0) return factory->NewJSArray(0);
i::Handle<i::FixedArray> result = factory->NewFixedArray(max_length);
int result_index = 0;
@ -7154,6 +7160,7 @@ i::Handle<i::JSArray> SetAsArray(i::Isolate* isolate, i::Object* table_obj,
i::Object* key = table->KeyAt(i);
if (key == the_hole) continue;
result->set(result_index++, key);
if (collect_key_values) result->set(result_index++, key);
}
}
DCHECK_GE(max_length, result_index);
@ -7169,7 +7176,8 @@ Local<Array> Set::AsArray() const {
i::Isolate* isolate = obj->GetIsolate();
LOG_API(isolate, Set, AsArray);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
return Utils::ToLocal(SetAsArray(isolate, obj->table(), 0));
return Utils::ToLocal(
SetAsArray(isolate, obj->table(), 0, SetAsArrayKind::kValues));
}
@ -9524,21 +9532,22 @@ v8::MaybeLocal<v8::Array> v8::Object::PreviewEntries(bool* is_key_value) {
i::Handle<i::JSWeakCollection>::cast(object), 0));
}
if (object->IsJSMapIterator()) {
i::Handle<i::JSMapIterator> iterator =
i::Handle<i::JSMapIterator>::cast(object);
i::Handle<i::JSMapIterator> it = i::Handle<i::JSMapIterator>::cast(object);
MapAsArrayKind const kind =
static_cast<MapAsArrayKind>(iterator->map()->instance_type());
static_cast<MapAsArrayKind>(it->map()->instance_type());
*is_key_value = kind == MapAsArrayKind::kEntries;
if (!iterator->HasMore()) return v8::Array::New(v8_isolate);
return Utils::ToLocal(MapAsArray(isolate, iterator->table(),
i::Smi::ToInt(iterator->index()), kind));
if (!it->HasMore()) return v8::Array::New(v8_isolate);
return Utils::ToLocal(
MapAsArray(isolate, it->table(), i::Smi::ToInt(it->index()), kind));
}
if (object->IsJSSetIterator()) {
i::Handle<i::JSSetIterator> it = i::Handle<i::JSSetIterator>::cast(object);
*is_key_value = false;
SetAsArrayKind const kind =
static_cast<SetAsArrayKind>(it->map()->instance_type());
*is_key_value = kind == SetAsArrayKind::kEntries;
if (!it->HasMore()) return v8::Array::New(v8_isolate);
return Utils::ToLocal(
SetAsArray(isolate, it->table(), i::Smi::ToInt(it->index())));
SetAsArray(isolate, it->table(), i::Smi::ToInt(it->index()), kind));
}
return v8::MaybeLocal<v8::Array>();
}

View File

@ -28853,7 +28853,7 @@ TEST(TestGetEmbeddedCodeRange) {
}
}
TEST(PreviewSetIteratorEntriesWithDeleted) {
TEST(PreviewSetKeysIteratorEntriesWithDeleted) {
LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local();
@ -28952,7 +28952,142 @@ TEST(PreviewSetIteratorEntriesWithDeleted) {
}
}
TEST(PreviewMapIteratorEntriesWithDeleted) {
TEST(PreviewSetValuesIteratorEntriesWithDeleted) {
LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local();
{
// Create set, delete entry, create iterator, preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); set.delete(1); set.values()")
->ToObject(context)
.ToLocalChecked();
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(2, entries->Length());
CHECK_EQ(2, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
CHECK_EQ(3, entries->Get(context, 1)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create set, create iterator, delete entry, preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); set.values()")
->ToObject(context)
.ToLocalChecked();
CompileRun("set.delete(1);");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(2, entries->Length());
CHECK_EQ(2, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
CHECK_EQ(3, entries->Get(context, 1)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create set, create iterator, delete entry, iterate, preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
->ToObject(context)
.ToLocalChecked();
CompileRun("set.delete(1); it.next();");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(1, entries->Length());
CHECK_EQ(3, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create set, create iterator, delete entry, iterate until empty, preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
->ToObject(context)
.ToLocalChecked();
CompileRun("set.delete(1); it.next(); it.next();");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(0, entries->Length());
}
{
// Create set, create iterator, delete entry, iterate, trigger rehash,
// preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
->ToObject(context)
.ToLocalChecked();
CompileRun("set.delete(1); it.next();");
CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(17, entries->Length());
for (uint32_t i = 0; i < 17; i++) {
CHECK_EQ(i + 3, entries->Get(context, i)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
}
}
TEST(PreviewMapEntriesIteratorEntries) {
LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local();
{
// Create set, delete entry, create entries iterator, preview.
v8::Local<v8::Object> iterator =
CompileRun("var set = new Set([1,2,3]); set.delete(2); set.entries()")
->ToObject(context)
.ToLocalChecked();
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(is_key);
CHECK_EQ(4, entries->Length());
uint32_t first = entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust();
uint32_t second = entries->Get(context, 2)
.ToLocalChecked()
->Int32Value(context)
.FromJust();
CHECK_EQ(1, first);
CHECK_EQ(3, second);
CHECK_EQ(first, entries->Get(context, 1)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
CHECK_EQ(second, entries->Get(context, 3)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
}
TEST(PreviewMapValuesIteratorEntriesWithDeleted) {
LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local();
@ -29066,3 +29201,94 @@ TEST(PreviewMapIteratorEntriesWithDeleted) {
}
}
}
TEST(PreviewMapKeysIteratorEntriesWithDeleted) {
LocalContext env;
v8::HandleScope handle_scope(env->GetIsolate());
v8::Local<v8::Context> context = env.local();
{
// Create map, delete entry, create iterator, preview.
v8::Local<v8::Object> iterator = CompileRun(
"var map = new Map();"
"var key = 1; map.set(key, {});"
"map.set(2, {}); map.set(3, {});"
"map.delete(key);"
"map.keys()")
->ToObject(context)
.ToLocalChecked();
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(2, entries->Length());
CHECK_EQ(2, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
CHECK_EQ(3, entries->Get(context, 1)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create map, create iterator, delete entry, preview.
v8::Local<v8::Object> iterator = CompileRun(
"var map = new Map();"
"var key = 1; map.set(key, {});"
"map.set(2, {}); map.set(3, {});"
"map.keys()")
->ToObject(context)
.ToLocalChecked();
CompileRun("map.delete(key);");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(2, entries->Length());
CHECK_EQ(2, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
CHECK_EQ(3, entries->Get(context, 1)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create map, create iterator, delete entry, iterate, preview.
v8::Local<v8::Object> iterator = CompileRun(
"var map = new Map();"
"var key = 1; map.set(key, {});"
"map.set(2, {}); map.set(3, {});"
"var it = map.keys(); it")
->ToObject(context)
.ToLocalChecked();
CompileRun("map.delete(key); it.next();");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(1, entries->Length());
CHECK_EQ(3, entries->Get(context, 0)
.ToLocalChecked()
->Int32Value(context)
.FromJust());
}
{
// Create map, create iterator, delete entry, iterate until empty, preview.
v8::Local<v8::Object> iterator = CompileRun(
"var map = new Map();"
"var key = 1; map.set(key, {});"
"map.set(2, {}); map.set(3, {});"
"var it = map.keys(); it")
->ToObject(context)
.ToLocalChecked();
CompileRun("map.delete(key); it.next(); it.next();");
bool is_key;
v8::Local<v8::Array> entries =
iterator->PreviewEntries(&is_key).ToLocalChecked();
CHECK(!is_key);
CHECK_EQ(0, entries->Length());
}
}

View File

@ -177,27 +177,39 @@ expression: (new Map([[1,2]])).entries()
}
]
expression: (new Set([[1,2]])).entries()
expression: (new Set([1,2])).entries()
[[Entries]]:
[
[0] : {
value : {
description : Array(2)
key : {
description : 1
overflow : false
properties : [
[0] : {
name : 0
type : number
value : 1
}
[1] : {
name : 1
type : number
value : 2
}
]
subtype : array
type : object
type : number
}
value : {
description : 1
overflow : false
properties : [
]
type : number
}
}
[1] : {
key : {
description : 2
overflow : false
properties : [
]
type : number
}
value : {
description : 2
overflow : false
properties : [
]
type : number
}
}
]

View File

@ -46,7 +46,7 @@ InspectorTest.runTestSuite([
function iteratorObject(next)
{
checkExpression("(new Map([[1,2]])).entries()")
.then(() => checkExpression("(new Set([[1,2]])).entries()"))
.then(() => checkExpression("(new Set([1,2])).entries()"))
.then(next);
},

View File

@ -572,6 +572,7 @@ expression: it = new Set([1,2]).keys(); it.next(); it
expression: it = new Set([1,2]).entries(); it.next(); it
[
[0] : {
key : 2
value : 2
}
]
@ -592,7 +593,7 @@ expression: it = new Set([1,2]).entries(); it.next(); it
name : 0
value : {
className : Object
description : 2
description : {2 => 2}
objectId : <objectId>
subtype : internal#entry
type : object