1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <string.h>
#include "gc/GC.h"
#include "js/RootingAPI.h"
#include "js/StableStringChars.h"
#include "js/String.h" // JS::StringToLinearString
#include "jsapi-tests/tests.h"
#include "vm/JSContext.h"
#include "vm/StringType.h"
#include "vm/JSContext-inl.h"
static bool SameChars(JSContext* cx, JSString* str1, JSString* str2,
size_t offset) {
JS::AutoCheckCannotGC nogc(cx);
const JS::Latin1Char* chars1 =
JS::StringToLinearString(cx, str1)->latin1Chars(nogc);
const JS::Latin1Char* chars2 =
JS::StringToLinearString(cx, str2)->latin1Chars(nogc);
return chars1 == chars2 + offset;
}
BEGIN_TEST(testDeduplication_ASSC) {
AutoGCParameter disableSemispace(cx, JSGC_SEMISPACE_NURSERY_ENABLED, 0);
// Test with a long enough string to avoid inline chars allocation.
const char text[] =
"Andthebeastshallcomeforthsurroundedbyaroilingcloudofvengeance."
"Thehouseoftheunbelieversshallberazedandtheyshallbescorchedtoth"
"eearth.Theirtagsshallblinkuntiltheendofdays.";
// Create a string to deduplicate later strings to.
JS::RootedString original(cx);
JS::RootedString str(cx);
JS::RootedString dep(cx);
JS::RootedString depdep(cx);
JS::RootedString str2(cx);
JS::RootedString dep2(cx);
JS::RootedString depdep2(cx);
if (!cx->zone()->allocNurseryStrings()) {
// This test requires nursery-allocated strings, so that they will go
// through the deduplication pass during minor GC.
return true;
}
{
// This test checks the behavior when GC is performed after allocating
// all the following strings.
// GC shouldn't happen in between them, even in compacting jobs.
js::gc::AutoSuppressGC suppress(cx);
original = JS_NewStringCopyZ(cx, text);
CHECK(original);
// Create a chain of dependent strings, with a base string whose contents
// match `original`'s.
str = JS_NewStringCopyZ(cx, text);
CHECK(str && !str->isTenured());
dep = JS_NewDependentString(cx, str, 10, 100);
CHECK(dep && !dep->isTenured());
depdep = JS_NewDependentString(cx, dep, 10, 80);
CHECK(depdep && !depdep->isTenured());
// Repeat. This one will not be prevented from deduplication.
str2 = JS_NewStringCopyZ(cx, text);
CHECK(str2 && !str2->isTenured());
dep2 = JS_NewDependentString(cx, str2, 10, 100);
CHECK(dep2 && !dep2->isTenured());
depdep2 = JS_NewDependentString(cx, dep2, 10, 80);
CHECK(depdep2 && !depdep2->isTenured());
}
// Initializing an AutoStableStringChars with `depdep` will prevent the
// owner of its chars (`str`) from being deduplicated, but only if the
// chars are stored in the malloc heap. Force `str` to be nondeduplicatable
// unconditionally to avoid depending on the exact set of things that are
// enabled.
str->setNonDeduplicatable();
JS::AutoStableStringChars stable(cx);
CHECK(stable.init(cx, depdep));
const JS::Latin1Char* chars = stable.latin1Chars();
CHECK(memcmp(chars, text + 20, 80 * sizeof(JS::Latin1Char)) == 0);
// `depdep` should share chars with `str` but not with `original`.
CHECK(SameChars(cx, depdep, str, 20));
CHECK(!SameChars(cx, depdep, original, 20));
// Same for `depdep2`.
CHECK(SameChars(cx, depdep2, str2, 20));
CHECK(!SameChars(cx, depdep2, original, 20));
// Do a minor GC that will deduplicate `str2` to `original`, and would have
// deduplicated `str` as well if it weren't prevented by the
// AutoStableStringChars.
cx->minorGC(JS::GCReason::API);
// `depdep` should still share chars with `str` but not with `original`.
CHECK(SameChars(cx, depdep, str, 20));
CHECK(!SameChars(cx, depdep, original, 20));
// `depdep2` should now share chars with both `str2` and `original`. Or with
// `str`, since it could legitimately have been detected to be identical to
// the tenured `depdep` and deduplicated to that.
CHECK(SameChars(cx, depdep2, str2, 20) || SameChars(cx, depdep2, str, 20));
CHECK(SameChars(cx, depdep2, original, 20) ||
SameChars(cx, depdep2, str, 20));
return true;
}
END_TEST(testDeduplication_ASSC)
|