Line data Source code
1 : // Copyright 2014 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/compiler/compiler-source-position-table.h"
6 : #include "src/compiler/js-context-specialization.h"
7 : #include "src/compiler/js-graph.h"
8 : #include "src/compiler/js-operator.h"
9 : #include "src/compiler/node-matchers.h"
10 : #include "src/compiler/node-properties.h"
11 : #include "src/heap/factory.h"
12 : #include "src/objects-inl.h"
13 : #include "src/property.h"
14 : #include "test/cctest/cctest.h"
15 : #include "test/cctest/compiler/function-tester.h"
16 : #include "test/cctest/compiler/graph-builder-tester.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace compiler {
21 :
22 80 : class ContextSpecializationTester : public HandleAndZoneScope {
23 : public:
24 120 : explicit ContextSpecializationTester(Maybe<OuterContext> context)
25 : : canonical_(main_isolate()),
26 40 : graph_(new (main_zone()) Graph(main_zone())),
27 : common_(main_zone()),
28 : javascript_(main_zone()),
29 : machine_(main_zone()),
30 : simplified_(main_zone()),
31 : jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
32 : &machine_),
33 : reducer_(main_zone(), graph()),
34 : js_heap_broker_(main_isolate(), main_zone()),
35 : spec_(&reducer_, jsgraph(), &js_heap_broker_, context,
36 400 : MaybeHandle<JSFunction>()) {}
37 :
38 : JSContextSpecialization* spec() { return &spec_; }
39 80 : Factory* factory() { return main_isolate()->factory(); }
40 : CommonOperatorBuilder* common() { return &common_; }
41 : JSOperatorBuilder* javascript() { return &javascript_; }
42 : SimplifiedOperatorBuilder* simplified() { return &simplified_; }
43 : JSGraph* jsgraph() { return &jsgraph_; }
44 : Graph* graph() { return graph_; }
45 :
46 : void CheckChangesToValue(Node* node, Handle<HeapObject> expected_value);
47 : void CheckContextInputAndDepthChanges(
48 : Node* node, Handle<Context> expected_new_context_object,
49 : size_t expected_new_depth);
50 : void CheckContextInputAndDepthChanges(Node* node, Node* expected_new_context,
51 : size_t expected_new_depth);
52 :
53 : private:
54 : CanonicalHandleScope canonical_;
55 : Graph* graph_;
56 : CommonOperatorBuilder common_;
57 : JSOperatorBuilder javascript_;
58 : MachineOperatorBuilder machine_;
59 : SimplifiedOperatorBuilder simplified_;
60 : JSGraph jsgraph_;
61 : GraphReducer reducer_;
62 : JSHeapBroker js_heap_broker_;
63 : JSContextSpecialization spec_;
64 : };
65 :
66 20 : void ContextSpecializationTester::CheckChangesToValue(
67 : Node* node, Handle<HeapObject> expected_value) {
68 20 : Reduction r = spec()->Reduce(node);
69 20 : CHECK(r.Changed());
70 : HeapObjectMatcher match(r.replacement());
71 20 : CHECK(match.HasValue());
72 60 : CHECK_EQ(*match.Value(), *expected_value);
73 20 : }
74 :
75 30 : void ContextSpecializationTester::CheckContextInputAndDepthChanges(
76 30 : Node* node, Handle<Context> expected_new_context_object,
77 : size_t expected_new_depth) {
78 30 : ContextAccess access = ContextAccessOf(node->op());
79 30 : Reduction r = spec()->Reduce(node);
80 30 : CHECK(r.Changed());
81 :
82 30 : Node* new_context = NodeProperties::GetContextInput(r.replacement());
83 30 : CHECK_EQ(IrOpcode::kHeapConstant, new_context->opcode());
84 : HeapObjectMatcher match(new_context);
85 90 : CHECK_EQ(Context::cast(*match.Value()), *expected_new_context_object);
86 :
87 30 : ContextAccess new_access = ContextAccessOf(r.replacement()->op());
88 30 : CHECK_EQ(new_access.depth(), expected_new_depth);
89 30 : CHECK_EQ(new_access.index(), access.index());
90 30 : CHECK_EQ(new_access.immutable(), access.immutable());
91 30 : }
92 :
93 85 : void ContextSpecializationTester::CheckContextInputAndDepthChanges(
94 85 : Node* node, Node* expected_new_context, size_t expected_new_depth) {
95 85 : ContextAccess access = ContextAccessOf(node->op());
96 85 : Reduction r = spec()->Reduce(node);
97 85 : CHECK(r.Changed());
98 :
99 85 : Node* new_context = NodeProperties::GetContextInput(r.replacement());
100 85 : CHECK_EQ(new_context, expected_new_context);
101 :
102 85 : ContextAccess new_access = ContextAccessOf(r.replacement()->op());
103 85 : CHECK_EQ(new_access.depth(), expected_new_depth);
104 85 : CHECK_EQ(new_access.index(), access.index());
105 85 : CHECK_EQ(new_access.immutable(), access.immutable());
106 85 : }
107 :
108 : static const int slot_index = Context::NATIVE_CONTEXT_INDEX;
109 :
110 28342 : TEST(ReduceJSLoadContext0) {
111 5 : ContextSpecializationTester t(Nothing<OuterContext>());
112 :
113 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
114 5 : t.graph()->SetStart(start);
115 :
116 : // Make a context and initialize it a bit for this test.
117 5 : Handle<Context> native = t.factory()->NewNativeContext();
118 5 : Handle<Context> subcontext1 = t.factory()->NewNativeContext();
119 5 : Handle<Context> subcontext2 = t.factory()->NewNativeContext();
120 5 : subcontext2->set_previous(*subcontext1);
121 5 : subcontext1->set_previous(*native);
122 5 : Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
123 : const int slot = Context::NATIVE_CONTEXT_INDEX;
124 10 : native->set(slot, *expected);
125 :
126 5 : Node* const_context = t.jsgraph()->Constant(native);
127 5 : Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
128 5 : Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
129 :
130 : {
131 : // Mutable slot, constant context, depth = 0 => do nothing.
132 : Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false),
133 5 : const_context, start);
134 5 : Reduction r = t.spec()->Reduce(load);
135 5 : CHECK(!r.Changed());
136 : }
137 :
138 : {
139 : // Mutable slot, non-constant context, depth = 0 => do nothing.
140 : Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false),
141 5 : param_context, start);
142 5 : Reduction r = t.spec()->Reduce(load);
143 5 : CHECK(!r.Changed());
144 : }
145 :
146 : {
147 : // Mutable slot, constant context, depth > 0 => fold-in parent context.
148 : Node* load = t.graph()->NewNode(
149 : t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false),
150 5 : deep_const_context, start);
151 5 : Reduction r = t.spec()->Reduce(load);
152 5 : CHECK(r.Changed());
153 5 : Node* new_context_input = NodeProperties::GetContextInput(r.replacement());
154 5 : CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
155 : HeapObjectMatcher match(new_context_input);
156 15 : CHECK_EQ(*native, Context::cast(*match.Value()));
157 5 : ContextAccess access = ContextAccessOf(r.replacement()->op());
158 10 : CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
159 5 : CHECK_EQ(0, static_cast<int>(access.depth()));
160 10 : CHECK_EQ(false, access.immutable());
161 : }
162 :
163 : {
164 : // Immutable slot, constant context, depth = 0 => specialize.
165 : Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, slot, true),
166 5 : const_context, start);
167 5 : Reduction r = t.spec()->Reduce(load);
168 5 : CHECK(r.Changed());
169 5 : CHECK(r.replacement() != load);
170 :
171 : HeapObjectMatcher match(r.replacement());
172 5 : CHECK(match.HasValue());
173 15 : CHECK_EQ(*expected, *match.Value());
174 5 : }
175 5 : }
176 :
177 28342 : TEST(ReduceJSLoadContext1) {
178 : // The graph's context chain ends in the incoming context parameter:
179 : //
180 : // context2 <-- context1 <-- context0 (= Parameter(0))
181 :
182 5 : ContextSpecializationTester t(Nothing<OuterContext>());
183 :
184 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
185 5 : t.graph()->SetStart(start);
186 5 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()), t.main_isolate());
187 : const i::compiler::Operator* create_function_context =
188 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
189 :
190 5 : Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
191 : Node* context1 =
192 5 : t.graph()->NewNode(create_function_context, context0, start, start);
193 : Node* context2 =
194 5 : t.graph()->NewNode(create_function_context, context1, start, start);
195 :
196 : {
197 : Node* load = t.graph()->NewNode(
198 5 : t.javascript()->LoadContext(0, slot_index, false), context2, start);
199 10 : CHECK(!t.spec()->Reduce(load).Changed());
200 : }
201 :
202 : {
203 : Node* load = t.graph()->NewNode(
204 5 : t.javascript()->LoadContext(0, slot_index, true), context2, start);
205 10 : CHECK(!t.spec()->Reduce(load).Changed());
206 : }
207 :
208 : {
209 : Node* load = t.graph()->NewNode(
210 5 : t.javascript()->LoadContext(1, slot_index, false), context2, start);
211 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
212 : }
213 :
214 : {
215 : Node* load = t.graph()->NewNode(
216 5 : t.javascript()->LoadContext(1, slot_index, true), context2, start);
217 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
218 : }
219 :
220 : {
221 : Node* load = t.graph()->NewNode(
222 5 : t.javascript()->LoadContext(2, slot_index, false), context2, start);
223 5 : t.CheckContextInputAndDepthChanges(load, context0, 0);
224 : }
225 :
226 : {
227 : Node* load = t.graph()->NewNode(
228 5 : t.javascript()->LoadContext(2, slot_index, true), context2, start);
229 5 : t.CheckContextInputAndDepthChanges(load, context0, 0);
230 : }
231 :
232 : {
233 : Node* load = t.graph()->NewNode(
234 5 : t.javascript()->LoadContext(3, slot_index, false), context2, start);
235 5 : t.CheckContextInputAndDepthChanges(load, context0, 1);
236 : }
237 :
238 : {
239 : Node* load = t.graph()->NewNode(
240 5 : t.javascript()->LoadContext(3, slot_index, true), context2, start);
241 5 : t.CheckContextInputAndDepthChanges(load, context0, 1);
242 5 : }
243 5 : }
244 :
245 28342 : TEST(ReduceJSLoadContext2) {
246 : // The graph's context chain ends in a constant context (context_object1),
247 : // which has another outer context (context_object0).
248 : //
249 : // context2 <-- context1 <-- context0 (= HeapConstant(context_object1))
250 : // context_object1 <~~ context_object0
251 :
252 5 : ContextSpecializationTester t(Nothing<OuterContext>());
253 :
254 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
255 5 : t.graph()->SetStart(start);
256 5 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()), t.main_isolate());
257 : const i::compiler::Operator* create_function_context =
258 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
259 :
260 5 : Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
261 5 : Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
262 :
263 5 : Handle<Context> context_object0 = t.factory()->NewNativeContext();
264 5 : Handle<Context> context_object1 = t.factory()->NewNativeContext();
265 5 : context_object1->set_previous(*context_object0);
266 10 : context_object0->set(slot_index, *slot_value0);
267 10 : context_object1->set(slot_index, *slot_value1);
268 :
269 5 : Node* context0 = t.jsgraph()->Constant(context_object1);
270 : Node* context1 =
271 5 : t.graph()->NewNode(create_function_context, context0, start, start);
272 : Node* context2 =
273 5 : t.graph()->NewNode(create_function_context, context1, start, start);
274 :
275 : {
276 : Node* load = t.graph()->NewNode(
277 5 : t.javascript()->LoadContext(0, slot_index, false), context2, start);
278 10 : CHECK(!t.spec()->Reduce(load).Changed());
279 : }
280 :
281 : {
282 : Node* load = t.graph()->NewNode(
283 5 : t.javascript()->LoadContext(0, slot_index, true), context2, start);
284 10 : CHECK(!t.spec()->Reduce(load).Changed());
285 : }
286 :
287 : {
288 : Node* load = t.graph()->NewNode(
289 5 : t.javascript()->LoadContext(1, slot_index, false), context2, start);
290 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
291 : }
292 :
293 : {
294 : Node* load = t.graph()->NewNode(
295 5 : t.javascript()->LoadContext(1, slot_index, true), context2, start);
296 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
297 : }
298 :
299 : {
300 : Node* load = t.graph()->NewNode(
301 5 : t.javascript()->LoadContext(2, slot_index, false), context2, start);
302 5 : t.CheckContextInputAndDepthChanges(load, context0, 0);
303 : }
304 :
305 : {
306 : Node* load = t.graph()->NewNode(
307 5 : t.javascript()->LoadContext(2, slot_index, true), context2, start);
308 5 : t.CheckChangesToValue(load, slot_value1);
309 : }
310 :
311 : {
312 : Node* load = t.graph()->NewNode(
313 5 : t.javascript()->LoadContext(3, slot_index, false), context2, start);
314 5 : t.CheckContextInputAndDepthChanges(load, context_object0, 0);
315 : }
316 :
317 : {
318 : Node* load = t.graph()->NewNode(
319 5 : t.javascript()->LoadContext(3, slot_index, true), context2, start);
320 5 : t.CheckChangesToValue(load, slot_value0);
321 5 : }
322 5 : }
323 :
324 28342 : TEST(ReduceJSLoadContext3) {
325 : // Like in ReduceJSLoadContext1, the graph's context chain ends in the
326 : // incoming context parameter. However, this time we provide a concrete
327 : // context for this parameter as the "specialization context". We choose
328 : // context_object2 from ReduceJSLoadContext2 for this, so almost all test
329 : // expectations are the same as in ReduceJSLoadContext2.
330 :
331 5 : HandleAndZoneScope handle_zone_scope;
332 5 : auto factory = handle_zone_scope.main_isolate()->factory();
333 :
334 5 : Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
335 5 : Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
336 :
337 5 : Handle<Context> context_object0 = factory->NewNativeContext();
338 5 : Handle<Context> context_object1 = factory->NewNativeContext();
339 5 : context_object1->set_previous(*context_object0);
340 10 : context_object0->set(slot_index, *slot_value0);
341 10 : context_object1->set(slot_index, *slot_value1);
342 :
343 10 : ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
344 :
345 5 : Node* start = t.graph()->NewNode(t.common()->Start(2));
346 5 : t.graph()->SetStart(start);
347 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()),
348 5 : handle_zone_scope.main_isolate());
349 : const i::compiler::Operator* create_function_context =
350 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
351 :
352 5 : Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
353 : Node* context1 =
354 5 : t.graph()->NewNode(create_function_context, context0, start, start);
355 : Node* context2 =
356 5 : t.graph()->NewNode(create_function_context, context1, start, start);
357 :
358 : {
359 : Node* load = t.graph()->NewNode(
360 5 : t.javascript()->LoadContext(0, slot_index, false), context2, start);
361 10 : CHECK(!t.spec()->Reduce(load).Changed());
362 : }
363 :
364 : {
365 : Node* load = t.graph()->NewNode(
366 5 : t.javascript()->LoadContext(0, slot_index, true), context2, start);
367 10 : CHECK(!t.spec()->Reduce(load).Changed());
368 : }
369 :
370 : {
371 : Node* load = t.graph()->NewNode(
372 5 : t.javascript()->LoadContext(1, slot_index, false), context2, start);
373 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
374 : }
375 :
376 : {
377 : Node* load = t.graph()->NewNode(
378 5 : t.javascript()->LoadContext(1, slot_index, true), context2, start);
379 5 : t.CheckContextInputAndDepthChanges(load, context1, 0);
380 : }
381 :
382 : {
383 : Node* load = t.graph()->NewNode(
384 5 : t.javascript()->LoadContext(2, slot_index, false), context2, start);
385 5 : t.CheckContextInputAndDepthChanges(load, context_object1, 0);
386 : }
387 :
388 : {
389 : Node* load = t.graph()->NewNode(
390 5 : t.javascript()->LoadContext(2, slot_index, true), context2, start);
391 5 : t.CheckChangesToValue(load, slot_value1);
392 : }
393 :
394 : {
395 : Node* load = t.graph()->NewNode(
396 5 : t.javascript()->LoadContext(3, slot_index, false), context2, start);
397 5 : t.CheckContextInputAndDepthChanges(load, context_object0, 0);
398 : }
399 :
400 : {
401 : Node* load = t.graph()->NewNode(
402 5 : t.javascript()->LoadContext(3, slot_index, true), context2, start);
403 5 : t.CheckChangesToValue(load, slot_value0);
404 5 : }
405 5 : }
406 :
407 28342 : TEST(ReduceJSStoreContext0) {
408 5 : ContextSpecializationTester t(Nothing<OuterContext>());
409 :
410 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
411 5 : t.graph()->SetStart(start);
412 :
413 : // Make a context and initialize it a bit for this test.
414 5 : Handle<Context> native = t.factory()->NewNativeContext();
415 5 : Handle<Context> subcontext1 = t.factory()->NewNativeContext();
416 5 : Handle<Context> subcontext2 = t.factory()->NewNativeContext();
417 5 : subcontext2->set_previous(*subcontext1);
418 5 : subcontext1->set_previous(*native);
419 5 : Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
420 : const int slot = Context::NATIVE_CONTEXT_INDEX;
421 10 : native->set(slot, *expected);
422 :
423 5 : Node* const_context = t.jsgraph()->Constant(native);
424 5 : Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
425 5 : Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
426 :
427 : {
428 : // Mutable slot, constant context, depth = 0 => do nothing.
429 : Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0),
430 5 : const_context, const_context, start, start);
431 5 : Reduction r = t.spec()->Reduce(load);
432 5 : CHECK(!r.Changed());
433 : }
434 :
435 : {
436 : // Mutable slot, non-constant context, depth = 0 => do nothing.
437 : Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0),
438 5 : param_context, param_context, start, start);
439 5 : Reduction r = t.spec()->Reduce(load);
440 5 : CHECK(!r.Changed());
441 : }
442 :
443 : {
444 : // Immutable slot, constant context, depth = 0 => do nothing.
445 : Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, slot),
446 5 : const_context, const_context, start, start);
447 5 : Reduction r = t.spec()->Reduce(load);
448 5 : CHECK(!r.Changed());
449 : }
450 :
451 : {
452 : // Mutable slot, constant context, depth > 0 => fold-in parent context.
453 : Node* load = t.graph()->NewNode(
454 : t.javascript()->StoreContext(2, Context::GLOBAL_EVAL_FUN_INDEX),
455 5 : deep_const_context, deep_const_context, start, start);
456 5 : Reduction r = t.spec()->Reduce(load);
457 5 : CHECK(r.Changed());
458 5 : Node* new_context_input = NodeProperties::GetContextInput(r.replacement());
459 5 : CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
460 : HeapObjectMatcher match(new_context_input);
461 15 : CHECK_EQ(*native, Context::cast(*match.Value()));
462 5 : ContextAccess access = ContextAccessOf(r.replacement()->op());
463 10 : CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
464 5 : CHECK_EQ(0, static_cast<int>(access.depth()));
465 10 : CHECK_EQ(false, access.immutable());
466 5 : }
467 5 : }
468 :
469 28342 : TEST(ReduceJSStoreContext1) {
470 5 : ContextSpecializationTester t(Nothing<OuterContext>());
471 :
472 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
473 5 : t.graph()->SetStart(start);
474 5 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()), t.main_isolate());
475 : const i::compiler::Operator* create_function_context =
476 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
477 :
478 5 : Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
479 : Node* context1 =
480 5 : t.graph()->NewNode(create_function_context, context0, start, start);
481 : Node* context2 =
482 5 : t.graph()->NewNode(create_function_context, context1, start, start);
483 :
484 : {
485 : Node* store =
486 : t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
487 5 : context2, context2, start, start);
488 10 : CHECK(!t.spec()->Reduce(store).Changed());
489 : }
490 :
491 : {
492 : Node* store =
493 : t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
494 5 : context2, context2, start, start);
495 5 : t.CheckContextInputAndDepthChanges(store, context1, 0);
496 : }
497 :
498 : {
499 : Node* store =
500 : t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
501 5 : context2, context2, start, start);
502 5 : t.CheckContextInputAndDepthChanges(store, context0, 0);
503 : }
504 :
505 : {
506 : Node* store =
507 : t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
508 5 : context2, context2, start, start);
509 5 : t.CheckContextInputAndDepthChanges(store, context0, 1);
510 5 : }
511 5 : }
512 :
513 28342 : TEST(ReduceJSStoreContext2) {
514 5 : ContextSpecializationTester t(Nothing<OuterContext>());
515 :
516 5 : Node* start = t.graph()->NewNode(t.common()->Start(0));
517 5 : t.graph()->SetStart(start);
518 5 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()), t.main_isolate());
519 : const i::compiler::Operator* create_function_context =
520 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
521 :
522 5 : Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
523 5 : Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
524 :
525 5 : Handle<Context> context_object0 = t.factory()->NewNativeContext();
526 5 : Handle<Context> context_object1 = t.factory()->NewNativeContext();
527 5 : context_object1->set_previous(*context_object0);
528 10 : context_object0->set(slot_index, *slot_value0);
529 10 : context_object1->set(slot_index, *slot_value1);
530 :
531 5 : Node* context0 = t.jsgraph()->Constant(context_object1);
532 : Node* context1 =
533 5 : t.graph()->NewNode(create_function_context, context0, start, start);
534 : Node* context2 =
535 5 : t.graph()->NewNode(create_function_context, context1, start, start);
536 :
537 : {
538 : Node* store =
539 : t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
540 5 : context2, context2, start, start);
541 10 : CHECK(!t.spec()->Reduce(store).Changed());
542 : }
543 :
544 : {
545 : Node* store =
546 : t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
547 5 : context2, context2, start, start);
548 5 : t.CheckContextInputAndDepthChanges(store, context1, 0);
549 : }
550 :
551 : {
552 : Node* store =
553 : t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
554 5 : context2, context2, start, start);
555 5 : t.CheckContextInputAndDepthChanges(store, context0, 0);
556 : }
557 :
558 : {
559 : Node* store =
560 : t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
561 5 : context2, context2, start, start);
562 5 : t.CheckContextInputAndDepthChanges(store, context_object0, 0);
563 5 : }
564 5 : }
565 :
566 28342 : TEST(ReduceJSStoreContext3) {
567 5 : HandleAndZoneScope handle_zone_scope;
568 5 : auto factory = handle_zone_scope.main_isolate()->factory();
569 :
570 5 : Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
571 5 : Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
572 :
573 5 : Handle<Context> context_object0 = factory->NewNativeContext();
574 5 : Handle<Context> context_object1 = factory->NewNativeContext();
575 5 : context_object1->set_previous(*context_object0);
576 10 : context_object0->set(slot_index, *slot_value0);
577 10 : context_object1->set(slot_index, *slot_value1);
578 :
579 10 : ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
580 :
581 5 : Node* start = t.graph()->NewNode(t.common()->Start(2));
582 5 : t.graph()->SetStart(start);
583 : Handle<ScopeInfo> empty(ScopeInfo::Empty(t.main_isolate()),
584 5 : handle_zone_scope.main_isolate());
585 : const i::compiler::Operator* create_function_context =
586 5 : t.javascript()->CreateFunctionContext(empty, 42, FUNCTION_SCOPE);
587 :
588 5 : Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
589 : Node* context1 =
590 5 : t.graph()->NewNode(create_function_context, context0, start, start);
591 : Node* context2 =
592 5 : t.graph()->NewNode(create_function_context, context1, start, start);
593 :
594 : {
595 : Node* store =
596 : t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
597 5 : context2, context2, start, start);
598 10 : CHECK(!t.spec()->Reduce(store).Changed());
599 : }
600 :
601 : {
602 : Node* store =
603 : t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
604 5 : context2, context2, start, start);
605 5 : t.CheckContextInputAndDepthChanges(store, context1, 0);
606 : }
607 :
608 : {
609 : Node* store =
610 : t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
611 5 : context2, context2, start, start);
612 5 : t.CheckContextInputAndDepthChanges(store, context_object1, 0);
613 : }
614 :
615 : {
616 : Node* store =
617 : t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
618 5 : context2, context2, start, start);
619 5 : t.CheckContextInputAndDepthChanges(store, context_object0, 0);
620 5 : }
621 5 : }
622 :
623 28342 : TEST(SpecializeJSFunction_ToConstant1) {
624 : FunctionTester T(
625 : "(function() { var x = 1; function inc(a)"
626 5 : " { return a + x; } return inc; })()");
627 :
628 5 : T.CheckCall(1.0, 0.0, 0.0);
629 5 : T.CheckCall(2.0, 1.0, 0.0);
630 5 : T.CheckCall(2.1, 1.1, 0.0);
631 5 : }
632 :
633 :
634 28342 : TEST(SpecializeJSFunction_ToConstant2) {
635 : FunctionTester T(
636 : "(function() { var x = 1.5; var y = 2.25; var z = 3.75;"
637 5 : " function f(a) { return a - x + y - z; } return f; })()");
638 :
639 5 : T.CheckCall(-3.0, 0.0, 0.0);
640 5 : T.CheckCall(-2.0, 1.0, 0.0);
641 5 : T.CheckCall(-1.9, 1.1, 0.0);
642 5 : }
643 :
644 :
645 28342 : TEST(SpecializeJSFunction_ToConstant3) {
646 : FunctionTester T(
647 : "(function() { var x = -11.5; function inc()"
648 : " { return (function(a) { return a + x; }); }"
649 5 : " return inc(); })()");
650 :
651 5 : T.CheckCall(-11.5, 0.0, 0.0);
652 5 : T.CheckCall(-10.5, 1.0, 0.0);
653 5 : T.CheckCall(-10.4, 1.1, 0.0);
654 5 : }
655 :
656 :
657 28342 : TEST(SpecializeJSFunction_ToConstant_uninit) {
658 : {
659 : FunctionTester T(
660 : "(function() { if (false) { var x = 1; } function inc(a)"
661 5 : " { return x; } return inc; })()"); // x is undefined!
662 : i::Isolate* isolate = CcTest::i_isolate();
663 15 : CHECK(
664 : T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsUndefined(isolate));
665 15 : CHECK(
666 : T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsUndefined(isolate));
667 15 : CHECK(T.Call(T.Val(-2.1), T.Val(0.0))
668 : .ToHandleChecked()
669 : ->IsUndefined(isolate));
670 : }
671 :
672 : {
673 : FunctionTester T(
674 : "(function() { if (false) { var x = 1; } function inc(a)"
675 5 : " { return a + x; } return inc; })()"); // x is undefined!
676 :
677 15 : CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
678 15 : CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
679 15 : CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsNaN());
680 : }
681 5 : }
682 :
683 : } // namespace compiler
684 : } // namespace internal
685 85011 : } // namespace v8
|