From 232697f1c77c09e2e5f9b98248c342403db4f703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Tue, 22 Oct 2019 15:59:07 +0200 Subject: [PATCH] deps: V8: cherry-pick ed40ab1 Original commit message: [regexp] Fix the order of named captures on the groups object Named capture properties on the groups object should be ordered by the capture index (and not alpha-sorted). This was accidentally broken in https://crrev.com/c/1687413. Bug: v8:9822,v8:9423 Change-Id: Iac6f866f077a1b7ce557ba47e8ba5d7e7014b3ce Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1864829 Auto-Submit: Jakob Gruber Reviewed-by: Peter Marshall Commit-Queue: Peter Marshall Cr-Commit-Position: refs/heads/master@{#64306} Refs: https://github.com/v8/v8/commit/ed40ab15830d1a501effd00f4d3ffe66bd9ef97f Fixes: https://github.com/nodejs/node/issues/29878 --- common.gypi | 2 +- deps/v8/src/regexp/regexp-ast.h | 2 +- deps/v8/src/regexp/regexp-parser.cc | 25 +++++++++++++++++-- .../mjsunit/harmony/regexp-named-captures.js | 9 +++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index 78a57d929198be..cc9107616a65a5 100644 --- a/common.gypi +++ b/common.gypi @@ -39,7 +39,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.14', + 'v8_embedder_string': '-node.15', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/regexp/regexp-ast.h b/deps/v8/src/regexp/regexp-ast.h index aab67cad154126..3de29512ea12b0 100644 --- a/deps/v8/src/regexp/regexp-ast.h +++ b/deps/v8/src/regexp/regexp-ast.h @@ -477,7 +477,7 @@ class RegExpCapture final : public RegExpTree { int max_match() override { return body_->max_match(); } RegExpTree* body() { return body_; } void set_body(RegExpTree* body) { body_ = body; } - int index() { return index_; } + int index() const { return index_; } const ZoneVector* name() const { return name_; } void set_name(const ZoneVector* name) { name_ = name; } static int StartRegister(int index) { return index * 2; } diff --git a/deps/v8/src/regexp/regexp-parser.cc b/deps/v8/src/regexp/regexp-parser.cc index d6e421cafa3f89..ec1beca84b7b4f 100644 --- a/deps/v8/src/regexp/regexp-parser.cc +++ b/deps/v8/src/regexp/regexp-parser.cc @@ -984,18 +984,39 @@ RegExpCapture* RegExpParser::GetCapture(int index) { return captures_->at(index - 1); } +namespace { + +struct RegExpCaptureIndexLess { + bool operator()(const RegExpCapture* lhs, const RegExpCapture* rhs) const { + DCHECK_NOT_NULL(lhs); + DCHECK_NOT_NULL(rhs); + return lhs->index() < rhs->index(); + } +}; + +} // namespace + Handle RegExpParser::CreateCaptureNameMap() { if (named_captures_ == nullptr || named_captures_->empty()) { return Handle(); } + // Named captures are sorted by name (because the set is used to ensure + // name uniqueness). But the capture name map must to be sorted by index. + + ZoneVector sorted_named_captures( + named_captures_->begin(), named_captures_->end(), zone()); + std::sort(sorted_named_captures.begin(), sorted_named_captures.end(), + RegExpCaptureIndexLess{}); + DCHECK_EQ(sorted_named_captures.size(), named_captures_->size()); + Factory* factory = isolate()->factory(); - int len = static_cast(named_captures_->size()) * 2; + int len = static_cast(sorted_named_captures.size()) * 2; Handle array = factory->NewFixedArray(len); int i = 0; - for (const auto& capture : *named_captures_) { + for (const auto& capture : sorted_named_captures) { Vector capture_name(capture->name()->data(), capture->name()->size()); // CSA code in ConstructNewResultFromMatchInfo requires these strings to be diff --git a/deps/v8/test/mjsunit/harmony/regexp-named-captures.js b/deps/v8/test/mjsunit/harmony/regexp-named-captures.js index e1fa60dca42737..f58bcd9d44c22a 100644 --- a/deps/v8/test/mjsunit/harmony/regexp-named-captures.js +++ b/deps/v8/test/mjsunit/harmony/regexp-named-captures.js @@ -419,6 +419,15 @@ function toSlowMode(re) { assertEquals("cd", "abcd".replace(re, "$<$1>")); } +// Named captures are ordered by capture index on the groups object. +// https://crbug.com/v8/9822 + +{ + const r = /(?.+)\s(?.+)/; + const s = 'example string'; + assertArrayEquals(["BKey", "AKey"], Object.keys(r.exec(s).groups)); +} + // Tests for 'groups' semantics on the regexp result object. // https://crbug.com/v8/7192