17a59ddfa2ef9f814c340156fe7d97dcaf12dee6
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGClobberize.h
1  /*
2  * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef DFGClobberize_h
27 #define DFGClobberize_h
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGAbstractHeap.h"
32 #include "DFGEdgeUsesStructure.h"
33 #include "DFGGraph.h"
34
35 namespace JSC { namespace DFG {
36
37 template<typename ReadFunctor, typename WriteFunctor>
38 void clobberizeForAllocation(ReadFunctor& read, WriteFunctor& write)
39 {
40     read(GCState);
41     read(BarrierState);
42     write(GCState);
43     write(BarrierState);
44 }
45
46 template<typename ReadFunctor, typename WriteFunctor>
47 void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write)
48 {
49     // Some notes:
50     //
51     // - We cannot hoist, or sink, anything that has effects. This means that the
52     //   easiest way of indicating that something cannot be hoisted is to claim
53     //   that it side-effects some miscellaneous thing.
54     //
55     // - We cannot hoist forward-exiting nodes without some additional effort. I
56     //   believe that what it comes down to is that forward-exiting generally have
57     //   their NodeExitsForward cleared upon hoist, except for forward-exiting
58     //   nodes that take bogus state as their input. Those are substantially
59     //   harder. We disable it for now. In the future we could enable it by having
60     //   versions of those nodes that backward-exit instead, but I'm not convinced
61     //   of the soundness.
62     //
63     // - Some nodes lie, and claim that they do not read the JSCell_structureID, JSCell_typeInfoFlags, etc.
64     //   These are nodes that use the structure in a way that does not depend on
65     //   things that change under structure transitions.
66     //
67     // - It's implicitly understood that OSR exits read the world. This is why we
68     //   generally don't move or eliminate stores. Every node can exit, so the
69     //   read set does not reflect things that would be read if we exited.
70     //   Instead, the read set reflects what the node will have to read if it
71     //   *doesn't* exit.
72     //
73     // - Broadly, we don't say that we're reading something if that something is
74     //   immutable.
75     //
76     // - We try to make this work even prior to type inference, just so that we
77     //   can use it for IR dumps. No promises on whether the answers are sound
78     //   prior to type inference - though they probably could be if we did some
79     //   small hacking.
80     
81     if (edgesUseStructure(graph, node))
82         read(JSCell_structureID);
83     
84     switch (node->op()) {
85     case JSConstant:
86     case DoubleConstant:
87     case Int52Constant:
88     case WeakJSConstant:
89     case Identity:
90     case Phantom:
91     case HardPhantom:
92     case BitAnd:
93     case BitOr:
94     case BitXor:
95     case BitLShift:
96     case BitRShift:
97     case BitURShift:
98     case ValueToInt32:
99     case ArithAdd:
100     case ArithSub:
101     case ArithNegate:
102     case ArithMul:
103     case ArithIMul:
104     case ArithDiv:
105     case ArithMod:
106     case ArithAbs:
107     case ArithMin:
108     case ArithMax:
109     case ArithSqrt:
110     case ArithFRound:
111     case ArithSin:
112     case ArithCos:
113     case GetScope:
114     case SkipScope:
115     case CheckFunction:
116     case StringCharCodeAt:
117     case StringFromCharCode:
118     case CompareEqConstant:
119     case CompareStrictEq:
120     case IsUndefined:
121     case IsBoolean:
122     case IsNumber:
123     case IsString:
124     case LogicalNot:
125     case ExtractOSREntryLocal:
126     case CheckInBounds:
127     case ConstantStoragePointer:
128     case UInt32ToNumber:
129     case DoubleAsInt32:
130     case Check:
131     case DoubleRep:
132     case ValueRep:
133     case Int52Rep:
134     case BooleanToNumber:
135     case FiatInt52:
136         return;
137         
138     case MovHint:
139     case ZombieHint:
140     case Upsilon:
141     case Phi:
142     case Flush:
143     case PhantomLocal:
144     case SetArgument:
145     case PhantomArguments:
146     case Jump:
147     case Branch:
148     case Switch:
149     case Throw:
150     case ForceOSRExit:
151     case Return:
152     case Unreachable:
153     case CheckTierUpInLoop:
154     case CheckTierUpAtReturn:
155     case CheckTierUpAndOSREnter:
156     case LoopHint:
157     case InvalidationPoint:
158     case Breakpoint:
159     case ProfileWillCall:
160     case ProfileDidCall:
161         write(SideState);
162         return;
163         
164     case VariableWatchpoint:
165     case TypedArrayWatchpoint:
166         read(Watchpoint_fire);
167         write(SideState);
168         return;
169         
170     case NotifyWrite:
171         write(Watchpoint_fire);
172         write(SideState);
173         return;
174
175     case CreateActivation:
176     case CreateArguments:
177         clobberizeForAllocation(read, write);
178         write(SideState);
179         write(Watchpoint_fire);
180         return;
181         
182     case FunctionReentryWatchpoint:
183         read(Watchpoint_fire);
184         return;
185
186     case ToThis:
187     case CreateThis:
188         read(MiscFields);
189         clobberizeForAllocation(read, write);
190         return;
191
192     case VarInjectionWatchpoint:
193     case AllocationProfileWatchpoint:
194     case IsObject:
195     case IsFunction:
196     case TypeOf:
197         read(MiscFields);
198         return;
199         
200     case GetById:
201     case GetByIdFlush:
202     case PutById:
203     case PutByIdFlush:
204     case PutByIdDirect:
205     case ArrayPush:
206     case ArrayPop:
207     case Call:
208     case Construct:
209     case ToPrimitive:
210     case In:
211     case GetMyArgumentsLengthSafe:
212     case GetMyArgumentByValSafe:
213     case ValueAdd:
214         read(World);
215         write(World);
216         return;
217         
218     case GetGetter:
219         read(GetterSetter_getter);
220         return;
221         
222     case GetSetter:
223         read(GetterSetter_setter);
224         return;
225         
226     case GetCallee:
227         read(AbstractHeap(Variables, JSStack::Callee));
228         return;
229         
230     case GetLocal:
231     case GetArgument:
232         read(AbstractHeap(Variables, node->local()));
233         return;
234         
235     case SetLocal:
236         write(AbstractHeap(Variables, node->local()));
237         return;
238         
239     case GetLocalUnlinked:
240         read(AbstractHeap(Variables, node->unlinkedLocal()));
241         return;
242         
243     case GetByVal: {
244         ArrayMode mode = node->arrayMode();
245         switch (mode.type()) {
246         case Array::SelectUsingPredictions:
247         case Array::Unprofiled:
248         case Array::Undecided:
249             // Assume the worst since we don't have profiling yet.
250             read(World);
251             write(World);
252             return;
253             
254         case Array::ForceExit:
255             write(SideState);
256             return;
257             
258         case Array::Generic:
259             read(World);
260             write(World);
261             return;
262             
263         case Array::String:
264             if (mode.isOutOfBounds()) {
265                 read(World);
266                 write(World);
267                 return;
268             }
269             // This appears to read nothing because it's only reading immutable data.
270             return;
271             
272         case Array::Arguments:
273             read(Arguments_registers);
274             read(Variables);
275             return;
276             
277         case Array::Int32:
278             if (mode.isInBounds()) {
279                 read(Butterfly_publicLength);
280                 read(Butterfly_vectorLength);
281                 read(IndexedInt32Properties);
282                 return;
283             }
284             read(World);
285             write(World);
286             return;
287             
288         case Array::Double:
289             if (mode.isInBounds()) {
290                 read(Butterfly_publicLength);
291                 read(Butterfly_vectorLength);
292                 read(IndexedDoubleProperties);
293                 return;
294             }
295             read(World);
296             write(World);
297             return;
298             
299         case Array::Contiguous:
300             if (mode.isInBounds()) {
301                 read(Butterfly_publicLength);
302                 read(Butterfly_vectorLength);
303                 read(IndexedContiguousProperties);
304                 return;
305             }
306             read(World);
307             write(World);
308             return;
309             
310         case Array::ArrayStorage:
311         case Array::SlowPutArrayStorage:
312             // Give up on life for now.
313             read(World);
314             write(World);
315             return;
316             
317         case Array::Int8Array:
318         case Array::Int16Array:
319         case Array::Int32Array:
320         case Array::Uint8Array:
321         case Array::Uint8ClampedArray:
322         case Array::Uint16Array:
323         case Array::Uint32Array:
324         case Array::Float32Array:
325         case Array::Float64Array:
326             read(TypedArrayProperties);
327             read(JSArrayBufferView_vector);
328             read(JSArrayBufferView_length);
329             return;
330         }
331         RELEASE_ASSERT_NOT_REACHED();
332         return;
333     }
334
335     case PutByValDirect:
336     case PutByVal:
337     case PutByValAlias: {
338         ArrayMode mode = node->arrayMode();
339         switch (mode.modeForPut().type()) {
340         case Array::SelectUsingPredictions:
341         case Array::Unprofiled:
342         case Array::Undecided:
343         case Array::String:
344             // Assume the worst since we don't have profiling yet.
345             read(World);
346             write(World);
347             return;
348             
349         case Array::ForceExit:
350             write(SideState);
351             return;
352             
353         case Array::Generic:
354             read(World);
355             write(World);
356             return;
357             
358         case Array::Arguments:
359             read(Arguments_registers);
360             read(Arguments_numArguments);
361             read(Arguments_slowArguments);
362             write(Variables);
363             return;
364             
365         case Array::Int32:
366             if (node->arrayMode().isOutOfBounds()) {
367                 read(World);
368                 write(World);
369                 return;
370             }
371             read(Butterfly_publicLength);
372             read(Butterfly_vectorLength);
373             read(IndexedInt32Properties);
374             write(IndexedInt32Properties);
375             return;
376             
377         case Array::Double:
378             if (node->arrayMode().isOutOfBounds()) {
379                 read(World);
380                 write(World);
381                 return;
382             }
383             read(Butterfly_publicLength);
384             read(Butterfly_vectorLength);
385             read(IndexedDoubleProperties);
386             write(IndexedDoubleProperties);
387             return;
388             
389         case Array::Contiguous:
390             if (node->arrayMode().isOutOfBounds()) {
391                 read(World);
392                 write(World);
393                 return;
394             }
395             read(Butterfly_publicLength);
396             read(Butterfly_vectorLength);
397             read(IndexedContiguousProperties);
398             write(IndexedContiguousProperties);
399             return;
400             
401         case Array::ArrayStorage:
402         case Array::SlowPutArrayStorage:
403             // Give up on life for now.
404             read(World);
405             write(World);
406             return;
407
408         case Array::Int8Array:
409         case Array::Int16Array:
410         case Array::Int32Array:
411         case Array::Uint8Array:
412         case Array::Uint8ClampedArray:
413         case Array::Uint16Array:
414         case Array::Uint32Array:
415         case Array::Float32Array:
416         case Array::Float64Array:
417             read(JSArrayBufferView_vector);
418             read(JSArrayBufferView_length);
419             write(TypedArrayProperties);
420             return;
421         }
422         RELEASE_ASSERT_NOT_REACHED();
423         return;
424     }
425         
426     case CheckStructure:
427     case StructureTransitionWatchpoint:
428     case InstanceOf:
429         read(JSCell_structureID);
430         return;
431
432     case CheckArray:
433         read(JSCell_indexingType);
434         read(JSCell_typeInfoType);
435         read(JSCell_structureID);
436         return;
437
438     case CheckHasInstance:
439         read(JSCell_typeInfoFlags);
440         return;
441
442     case CheckExecutable:
443         read(JSFunction_executable);
444         return;
445         
446     case PutStructure:
447     case PhantomPutStructure:
448         write(JSCell_structureID);
449         write(JSCell_typeInfoType);
450         write(JSCell_typeInfoFlags);
451         write(JSCell_indexingType);
452         return;
453         
454     case AllocatePropertyStorage:
455         write(JSObject_butterfly);
456         clobberizeForAllocation(read, write);
457         return;
458         
459     case ReallocatePropertyStorage:
460         read(JSObject_butterfly);
461         write(JSObject_butterfly);
462         clobberizeForAllocation(read, write);
463         return;
464         
465     case GetButterfly:
466         read(JSObject_butterfly);
467         return;
468         
469     case Arrayify:
470     case ArrayifyToStructure:
471         read(JSCell_structureID);
472         read(JSCell_indexingType);
473         read(JSObject_butterfly);
474         write(JSCell_structureID);
475         write(JSCell_indexingType);
476         write(JSObject_butterfly);
477         write(Watchpoint_fire);
478         clobberizeForAllocation(read, write);
479         return;
480         
481     case GetIndexedPropertyStorage:
482         if (node->arrayMode().type() == Array::String)
483             return;
484         read(JSArrayBufferView_vector);
485         return;
486         
487     case GetTypedArrayByteOffset:
488         read(JSArrayBufferView_vector);
489         read(JSArrayBufferView_mode);
490         read(Butterfly_arrayBuffer);
491         read(ArrayBuffer_data);
492         return;
493         
494     case GetByOffset:
495     case GetGetterSetterByOffset:
496         read(AbstractHeap(NamedProperties, graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber));
497         return;
498         
499     case MultiGetByOffset:
500         read(JSCell_structureID);
501         read(JSObject_butterfly);
502         read(AbstractHeap(NamedProperties, node->multiGetByOffsetData().identifierNumber));
503         return;
504         
505     case MultiPutByOffset:
506         read(JSCell_structureID);
507         read(JSObject_butterfly);
508         write(AbstractHeap(NamedProperties, node->multiPutByOffsetData().identifierNumber));
509         if (node->multiPutByOffsetData().writesStructures())
510             write(JSCell_structureID);
511         if (node->multiPutByOffsetData().reallocatesStorage()) {
512             write(JSObject_butterfly);
513             clobberizeForAllocation(read, write);
514         }
515         return;
516         
517     case PutByOffset:
518         write(AbstractHeap(NamedProperties, graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber));
519         return;
520         
521     case GetArrayLength: {
522         ArrayMode mode = node->arrayMode();
523         switch (mode.type()) {
524         case Array::Int32:
525         case Array::Double:
526         case Array::Contiguous:
527         case Array::ArrayStorage:
528         case Array::SlowPutArrayStorage:
529             read(Butterfly_publicLength);
530             return;
531             
532         case Array::String:
533             return;
534             
535         case Array::Arguments:
536             read(Arguments_overrideLength);
537             read(Arguments_numArguments);
538             return;
539             
540         default:
541             read(JSArrayBufferView_length);
542             return;
543         }
544     }
545         
546     case GetMyScope:
547         read(AbstractHeap(Variables, JSStack::ScopeChain));
548         return;
549         
550     case SkipTopScope:
551         read(AbstractHeap(Variables, graph.activationRegister()));
552         return;
553         
554     case GetClosureRegisters:
555         read(JSVariableObject_registers);
556         return;
557         
558     case GetClosureVar:
559         read(AbstractHeap(Variables, node->varNumber()));
560         return;
561         
562     case PutClosureVar:
563         write(AbstractHeap(Variables, node->varNumber()));
564         return;
565         
566     case GetGlobalVar:
567         read(AbstractHeap(Absolute, node->registerPointer()));
568         return;
569         
570     case PutGlobalVar:
571         write(AbstractHeap(Absolute, node->registerPointer()));
572         return;
573
574     case NewObject:
575     case NewArray:
576     case NewArrayWithSize:
577     case NewArrayBuffer:
578     case NewRegexp:
579     case NewStringObject:
580     case MakeRope:
581     case NewFunctionNoCheck:
582     case NewFunction:
583     case NewFunctionExpression:
584         clobberizeForAllocation(read, write);
585         return;
586         
587     case NewTypedArray:
588         clobberizeForAllocation(read, write);
589         switch (node->child1().useKind()) {
590         case Int32Use:
591             return;
592         case UntypedUse:
593             read(World);
594             write(World);
595             return;
596         default:
597             RELEASE_ASSERT_NOT_REACHED();
598             return;
599         }
600         
601     case RegExpExec:
602     case RegExpTest:
603         read(RegExpState);
604         write(RegExpState);
605         return;
606
607     case StringCharAt:
608         if (node->arrayMode().isOutOfBounds()) {
609             read(World);
610             write(World);
611             return;
612         }
613         return;
614         
615     case CompareEq:
616     case CompareLess:
617     case CompareLessEq:
618     case CompareGreater:
619     case CompareGreaterEq:
620         if (!node->isBinaryUseKind(UntypedUse))
621             return;
622         read(World);
623         write(World);
624         return;
625         
626     case ToString:
627         switch (node->child1().useKind()) {
628         case StringObjectUse:
629         case StringOrStringObjectUse:
630             return;
631             
632         case CellUse:
633         case UntypedUse:
634             read(World);
635             write(World);
636             return;
637             
638         default:
639             RELEASE_ASSERT_NOT_REACHED();
640             return;
641         }
642
643     case TearOffActivation:
644         write(JSVariableObject_registers);
645         return;
646         
647     case TearOffArguments:
648         write(Arguments_registers);
649         return;
650         
651     case GetMyArgumentsLength:
652         read(AbstractHeap(Variables, graph.argumentsRegisterFor(node->origin.semantic)));
653         read(AbstractHeap(Variables, JSStack::ArgumentCount));
654         return;
655         
656     case GetMyArgumentByVal:
657         read(Variables);
658         return;
659         
660     case CheckArgumentsNotCreated:
661         read(AbstractHeap(Variables, graph.argumentsRegisterFor(node->origin.semantic)));
662         return;
663
664     case ThrowReferenceError:
665         write(SideState);
666         clobberizeForAllocation(read, write);
667         return;
668         
669     case CountExecution:
670     case CheckWatchdogTimer:
671         read(InternalState);
672         write(InternalState);
673         return;
674
675     case StoreBarrier:
676     case StoreBarrierWithNullCheck:
677         read(BarrierState);
678         write(BarrierState);
679         return;
680         
681     case LastNodeType:
682         RELEASE_ASSERT_NOT_REACHED();
683         return;
684     }
685     
686     RELEASE_ASSERT_NOT_REACHED();
687 }
688
689 class NoOpClobberize {
690 public:
691     NoOpClobberize() { }
692     void operator()(AbstractHeap) { }
693 };
694
695 class CheckClobberize {
696 public:
697     CheckClobberize()
698         : m_result(false)
699     {
700     }
701     
702     void operator()(AbstractHeap) { m_result = true; }
703     
704     bool result() const { return m_result; }
705     
706 private:
707     bool m_result;
708 };
709
710 bool doesWrites(Graph&, Node*);
711
712 class AbstractHeapOverlaps {
713 public:
714     AbstractHeapOverlaps(AbstractHeap heap)
715         : m_heap(heap)
716         , m_result(false)
717     {
718     }
719     
720     void operator()(AbstractHeap otherHeap)
721     {
722         if (m_result)
723             return;
724         m_result = m_heap.overlaps(otherHeap);
725     }
726     
727     bool result() const { return m_result; }
728
729 private:
730     AbstractHeap m_heap;
731     bool m_result;
732 };
733
734 bool writesOverlap(Graph&, Node*, AbstractHeap);
735
736 } } // namespace JSC::DFG
737
738 #endif // ENABLE(DFG_JIT)
739
740 #endif // DFGClobberize_h
741