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