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 #include "src/execution/isolate.h"
6 #include "src/handles/handles-inl.h"
7 #include "src/handles/handles.h"
8 #include "src/heap/local-heap.h"
9 #include "src/objects/foreign-inl.h"
10 #include "src/objects/managed.h"
11 #include "src/objects/maybe-object.h"
12 #include "src/objects/object-macros.h"
13
14 namespace v8 {
15 namespace internal {
16
17 // ------- Test simple argument evaluation order problems ---------
18
Safepoint()19 void Safepoint() { LocalHeap::Current()->Safepoint(); }
20
CauseGC(Handle<Object> obj,Isolate * isolate)21 Handle<Object> CauseGC(Handle<Object> obj, Isolate* isolate) {
22 isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
23
24 return obj;
25 }
26
CauseGCRaw(Object obj,Isolate * isolate)27 Object CauseGCRaw(Object obj, Isolate* isolate) {
28 isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
29
30 return obj;
31 }
32
CauseGCManaged(int i,Isolate * isolate)33 Managed<Smi> CauseGCManaged(int i, Isolate* isolate) {
34 isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
35
36 return Managed<Smi>::cast(Smi::FromInt(i));
37 }
38
TwoArgumentsFunction(Object a,Object b)39 void TwoArgumentsFunction(Object a, Object b) {
40 a.Print();
41 b.Print();
42 }
43
TestTwoArguments(Isolate * isolate)44 void TestTwoArguments(Isolate* isolate) {
45 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
46 Handle<JSObject> obj2 = isolate->factory()->NewJSObjectWithNullProto();
47 // Should cause warning.
48 TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate));
49 }
50
TwoSizeTArgumentsFunction(size_t a,size_t b)51 void TwoSizeTArgumentsFunction(size_t a, size_t b) {
52 USE(a);
53 USE(b);
54 }
55
TestTwoSizeTArguments(Isolate * isolate)56 void TestTwoSizeTArguments(Isolate* isolate) {
57 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
58 Handle<JSObject> obj2 = isolate->factory()->NewJSObjectWithNullProto();
59 // Should cause warning.
60 TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)),
61 sizeof(*CauseGC(obj2, isolate)));
62 }
63
64 // --------- Test problems with method arguments ----------
65
66 class SomeObject : public Object {
67 public:
Method(Object a)68 void Method(Object a) { a.Print(); }
69
operator =(const Object & b)70 SomeObject& operator=(const Object& b) {
71 this->Print();
72 return *this;
73 }
74
75 DECL_CAST(SomeObject)
76
77 OBJECT_CONSTRUCTORS(SomeObject, Object);
78 };
79
TestMethodCall(Isolate * isolate)80 void TestMethodCall(Isolate* isolate) {
81 SomeObject obj;
82 Handle<SomeObject> so = handle(obj, isolate);
83 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
84 // Should cause warning.
85 so->Method(*CauseGC(obj1, isolate));
86 // Should cause warning.
87 so->Method(CauseGCRaw(*obj1, isolate));
88 }
89
TestOperatorCall(Isolate * isolate)90 void TestOperatorCall(Isolate* isolate) {
91 SomeObject obj;
92 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
93 // Should not cause warning.
94 obj = *CauseGC(obj1, isolate);
95 }
96
97 // --------- Test for templated sub-classes of Object ----------
98
TestFollowingTemplates(Isolate * isolate)99 void TestFollowingTemplates(Isolate* isolate) {
100 // Should cause warning.
101 CauseGCManaged(42, isolate);
102 }
103
104 // --------- Test for correctly resolving virtual methods ----------
105
106 class BaseObject {
107 public:
VirtualCauseGC(Handle<Object> obj,Isolate * isolate)108 virtual Handle<Object> VirtualCauseGC(Handle<Object> obj, Isolate* isolate) {
109 return obj;
110 }
111 };
112
113 class DerivedObject : public BaseObject {
114 public:
VirtualCauseGC(Handle<Object> obj,Isolate * isolate)115 Handle<Object> VirtualCauseGC(Handle<Object> obj, Isolate* isolate) override {
116 isolate->heap()->CollectGarbage(OLD_SPACE,
117 GarbageCollectionReason::kTesting);
118
119 return obj;
120 }
121 };
122
TestFollowingVirtualFunctions(Isolate * isolate)123 void TestFollowingVirtualFunctions(Isolate* isolate) {
124 DerivedObject derived;
125 BaseObject* base = &derived;
126 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
127
128 SomeObject so;
129 Handle<SomeObject> so_handle = handle(so, isolate);
130 // Should cause warning.
131 so_handle->Method(*derived.VirtualCauseGC(obj1, isolate));
132 // Should cause warning.
133 so_handle->Method(*base->VirtualCauseGC(obj1, isolate));
134 }
135
136 // --------- Test for correctly resolving static methods ----------
137
138 class SomeClass {
139 public:
StaticCauseGC(Handle<Object> obj,Isolate * isolate)140 static Handle<Object> StaticCauseGC(Handle<Object> obj, Isolate* isolate) {
141 isolate->heap()->CollectGarbage(OLD_SPACE,
142 GarbageCollectionReason::kTesting);
143
144 return obj;
145 }
146 };
147
TestFollowingStaticFunctions(Isolate * isolate)148 void TestFollowingStaticFunctions(Isolate* isolate) {
149 SomeObject so;
150 Handle<SomeObject> so_handle = handle(so, isolate);
151
152 Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
153 // Should cause warning.
154 so_handle->Method(*SomeClass::StaticCauseGC(obj1, isolate));
155 }
156
157 // --------- Test basic dead variable analysis ----------
158
TestDeadVarAnalysis(Isolate * isolate)159 void TestDeadVarAnalysis(Isolate* isolate) {
160 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
161 CauseGCRaw(raw_obj, isolate);
162
163 // Should cause warning.
164 raw_obj.Print();
165 }
166
TestDeadVarBecauseOfSafepointAnalysis(Isolate * isolate)167 void TestDeadVarBecauseOfSafepointAnalysis(Isolate* isolate) {
168 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
169 Safepoint();
170
171 // Should cause warning.
172 raw_obj.Print();
173 }
174
TestGuardedDeadVarAnalysis(Isolate * isolate)175 void TestGuardedDeadVarAnalysis(Isolate* isolate) {
176 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
177
178 // Note: having DisableGCMole with the same function as CauseGC
179 // normally doesn't make sense, but we want to test whether the guards
180 // are recognized by GCMole.
181 DisableGCMole no_gc_mole;
182 CauseGCRaw(raw_obj, isolate);
183
184 // Shouldn't cause warning.
185 raw_obj.Print();
186 }
187
TestGuardedDeadVarAnalysis2(Isolate * isolate)188 void TestGuardedDeadVarAnalysis2(Isolate* isolate) {
189 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
190
191 // Note: having DisallowGarbageCollection with the same function as CauseGC
192 // normally doesn't make sense, but we want to test whether the guards
193 // are recognized by GCMole.
194 DisallowGarbageCollection no_gc;
195 CauseGCRaw(raw_obj, isolate);
196
197 // Should cause warning.
198 raw_obj.Print();
199 }
200
TestGuardedAgainstSafepointDeadVarAnalysis(Isolate * isolate)201 void TestGuardedAgainstSafepointDeadVarAnalysis(Isolate* isolate) {
202 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
203
204 // Note: having DisableGCMole with the same function as CauseGC
205 // normally doesn't make sense, but we want to test whether the guards
206 // are recognized by GCMole.
207 DisableGCMole no_gc_mole;
208 Safepoint();
209
210 // Shouldn't cause warning.
211 raw_obj.Print();
212 }
213
TestGuardedAgainstSafepointDeadVarAnalysis2(Isolate * isolate)214 void TestGuardedAgainstSafepointDeadVarAnalysis2(Isolate* isolate) {
215 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
216
217 // Note: having DisallowGarbageCollection with the same function as CauseGC
218 // normally doesn't make sense, but we want to test whether the guards
219 // are recognized by GCMole.
220 DisallowGarbageCollection no_gc;
221 Safepoint();
222
223 // Should cause warning.
224 raw_obj.Print();
225 }
226
TestGuardedAgainstSafepointDeadVarAnalysis3(Isolate * isolate)227 void TestGuardedAgainstSafepointDeadVarAnalysis3(Isolate* isolate) {
228 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
229 // Note: having DisallowGarbageCollection with the same function as CauseGC
230 // normally doesn't make sense, but we want to test whether the guards
231 // are recognized by GCMole.
232 DisallowGarbageCollection no_gc;
233 Safepoint();
234 // Should cause warning.
235 raw_obj.Print();
236 {
237 DisableGCMole no_gc_mole;
238 // Shouldn't cause warning.
239 raw_obj.Print();
240 }
241 // Should cause warning.
242 raw_obj.Print();
243 }
244
TestOnlyHeapGuardedDeadVarAnalysisInCompound(Isolate * isolate)245 void TestOnlyHeapGuardedDeadVarAnalysisInCompound(Isolate* isolate) {
246 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
247 // {DisallowHeapAccess} has a {DisallowHeapAllocation}, but no
248 // {DisallowSafepoints}, so it could see objects move due to safepoints.
249 DisallowHeapAccess no_gc;
250 CauseGCRaw(raw_obj, isolate);
251 // Should cause warning.
252 raw_obj.Print();
253 }
254
TestOnlyHeapGuardedDeadVarAnalysisInCompound2(Isolate * isolate)255 void TestOnlyHeapGuardedDeadVarAnalysisInCompound2(Isolate* isolate) {
256 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
257 // {DisallowHeapAccess} has a {DisallowHeapAllocation}, but no
258 // {DisallowSafepoints}, so it could see objects move due to safepoints.
259 DisallowHeapAccess no_gc;
260 CauseGCRaw(raw_obj, isolate);
261 // Should cause warning.
262 raw_obj.Print();
263 DisableGCMole no_gc_mole;
264 // Should cause warning.
265 raw_obj.Print();
266 }
267
TestGuardedDeadVarAnalysisNested(JSObject raw_obj,Isolate * isolate)268 void TestGuardedDeadVarAnalysisNested(JSObject raw_obj, Isolate* isolate) {
269 CauseGCRaw(raw_obj, isolate);
270 // Should cause warning.
271 raw_obj.Print();
272 }
273
TestGuardedDeadVarAnalysisCaller(Isolate * isolate)274 void TestGuardedDeadVarAnalysisCaller(Isolate* isolate) {
275 DisableGCMole no_gc_mole;
276 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
277 TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
278 // Shouldn't cause warning.
279 raw_obj.Print();
280 }
281
TestGuardedDeadVarAnalysisCaller2(Isolate * isolate)282 void TestGuardedDeadVarAnalysisCaller2(Isolate* isolate) {
283 DisallowGarbageCollection no_gc;
284 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
285 TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
286 // Should cause warning.
287 raw_obj.Print();
288 }
289
TestGuardedDeadVarAnalysisCaller3(Isolate * isolate)290 void TestGuardedDeadVarAnalysisCaller3(Isolate* isolate) {
291 DisallowHeapAccess no_gc;
292 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
293 TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
294 // Should cause warning.
295 raw_obj.Print();
296 }
297
TestGuardedDeadVarAnalysisCaller4(Isolate * isolate)298 void TestGuardedDeadVarAnalysisCaller4(Isolate* isolate) {
299 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
300 TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
301 // Should cause warning.
302 raw_obj.Print();
303 }
304
GuardedAllocation(Isolate * isolate)305 JSObject GuardedAllocation(Isolate* isolate) {
306 DisallowGarbageCollection no_gc;
307 return *isolate->factory()->NewJSObjectWithNullProto();
308 }
309
GuardedAllocation2(Isolate * isolate)310 JSObject GuardedAllocation2(Isolate* isolate) {
311 DisableGCMole no_gc_mole;
312 return *isolate->factory()->NewJSObjectWithNullProto();
313 }
314
TestNestedDeadVarAnalysis(Isolate * isolate)315 void TestNestedDeadVarAnalysis(Isolate* isolate) {
316 JSObject raw_obj = GuardedAllocation(isolate);
317 CauseGCRaw(raw_obj, isolate);
318 // Should cause warning.
319 raw_obj.Print();
320 }
321
TestNestedDeadVarAnalysis2(Isolate * isolate)322 void TestNestedDeadVarAnalysis2(Isolate* isolate) {
323 DisableGCMole no_gc_mole;
324 JSObject raw_obj = GuardedAllocation(isolate);
325 CauseGCRaw(raw_obj, isolate);
326 // Shouldn't cause warning.
327 raw_obj.Print();
328 }
329
330 // Test that putting a guard in the middle of the function doesn't
331 // mistakenly cover the whole scope of the raw variable.
TestGuardedDeadVarAnalysisMidFunction(Isolate * isolate)332 void TestGuardedDeadVarAnalysisMidFunction(Isolate* isolate) {
333 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
334 CauseGCRaw(raw_obj, isolate);
335 // Guarding the rest of the function from triggering a GC.
336 DisallowGarbageCollection no_gc;
337 // Should cause warning.
338 raw_obj.Print();
339 }
340
341 // Test that putting a guard in the middle of the function doesn't
342 // mistakenly cover the whole scope of the raw variable.
TestGuardedDeadVarAnalysisMidFunction2(Isolate * isolate)343 void TestGuardedDeadVarAnalysisMidFunction2(Isolate* isolate) {
344 JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
345 CauseGCRaw(raw_obj, isolate);
346 // Guarding the rest of the function from triggering a GC.
347 DisableGCMole no_gc_mole;
348 // Should cause warning.
349 raw_obj.Print();
350 }
351
352 } // namespace internal
353 } // namespace v8
354