Skip to content

Commit aecd843

Browse files
schuayCommit Bot
authored andcommitted
[compiler] Fix RegExpPrototypeTest reduction
This reduction relies on a known object layout of the regexp instance in order to access the lastIndex field through a statically-determined offset. Prior to this CL, we checked only for instance types, not for the map, and thus it was possible to read garbage from either inside or outside the current object. Bug: chromium:1024758,v8:7779 Change-Id: I1eec8220797f443bdf3d05804e54f33b21fa2f00 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1924353 Reviewed-by: Georg Neis <[email protected]> Reviewed-by: Sigurd Schneider <[email protected]> Commit-Queue: Jakob Gruber <[email protected]> Cr-Commit-Position: refs/heads/master@{#65039}
1 parent 67d3100 commit aecd843

5 files changed

Lines changed: 53 additions & 4 deletions

File tree

src/compiler/heap-refs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class ContextRef : public HeapObjectRef {
389389
V(JSFunction, object_function) \
390390
V(JSFunction, promise_function) \
391391
V(JSFunction, promise_then) \
392+
V(JSFunction, regexp_function) \
392393
V(JSFunction, string_function) \
393394
V(JSFunction, symbol_function) \
394395
V(JSGlobalObject, global_object) \

src/compiler/js-call-reducer.cc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7067,11 +7067,14 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
70677067
Node* control = NodeProperties::GetControlInput(node);
70687068
Node* regexp = NodeProperties::GetValueInput(node, 1);
70697069

7070+
// Only the initial JSRegExp map is valid here, since the following lastIndex
7071+
// check as well as the lowered builtin call rely on a known location of the
7072+
// lastIndex field.
7073+
Handle<Map> regexp_initial_map =
7074+
native_context().regexp_function().initial_map().object();
7075+
70707076
MapInference inference(broker(), regexp, effect);
7071-
if (!inference.HaveMaps() ||
7072-
!inference.AllOfInstanceTypes(InstanceTypeChecker::IsJSRegExp)) {
7073-
return inference.NoChange();
7074-
}
7077+
if (!inference.Is(regexp_initial_map)) return inference.NoChange();
70757078
MapHandles const& regexp_maps = inference.GetMaps();
70767079

70777080
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());

src/compiler/map-inference.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ MapHandles const& MapInference::GetMaps() {
9191
return maps_;
9292
}
9393

94+
bool MapInference::Is(Handle<Map> expected_map) {
95+
if (!HaveMaps()) return false;
96+
const MapHandles& maps = GetMaps();
97+
if (maps.size() != 1) return false;
98+
return maps[0].equals(expected_map);
99+
}
100+
94101
void MapInference::InsertMapChecks(JSGraph* jsgraph, Node** effect,
95102
Node* control,
96103
const FeedbackSource& feedback) {

src/compiler/map-inference.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class MapInference {
5555
V8_WARN_UNUSED_RESULT MapHandles const& GetMaps();
5656
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypes(
5757
std::function<bool(InstanceType)> f);
58+
V8_WARN_UNUSED_RESULT bool Is(Handle<Map> expected_map);
5859

5960
// These methods provide a guard.
6061
//
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2019 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
//
5+
// Flags: --allow-natives-syntax
6+
7+
function f() {
8+
return r.test("abc");
9+
}
10+
11+
function to_dict(o) {
12+
r.a = 42;
13+
r.b = 42;
14+
delete r.a;
15+
}
16+
17+
function to_fast(o) {
18+
const obj = {};
19+
const obj2 = {};
20+
delete o.a;
21+
obj.__proto__ = o;
22+
obj[0] = 1;
23+
obj.__proto__ = obj2;
24+
delete obj[0];
25+
return o;
26+
}
27+
28+
// Shrink the instance size by first transitioning to dictionary properties,
29+
// then back to fast properties.
30+
const r = /./;
31+
to_dict(r);
32+
to_fast(r);
33+
34+
%PrepareFunctionForOptimization(f);
35+
assertTrue(f());
36+
%OptimizeFunctionOnNextCall(f);
37+
assertTrue(f());

0 commit comments

Comments
 (0)