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