|
Lines 1-3
Source/JavaScriptCore/ChangeLog_sec1
|
|
|
1 |
2016-05-03 Filip Pizlo <fpizlo@apple.com> |
| 2 |
|
| 3 |
References from code to Structures should be stronger than weak |
| 4 |
https://bugs.webkit.org/show_bug.cgi?id=157324 |
| 5 |
|
| 6 |
Reviewed by NOBODY (OOPS!). |
| 7 |
|
| 8 |
If code refers to a Structure and the Structure dies, then previously we'd kill the code. |
| 9 |
This makes sense because the Structure could be the only thing left referring to some global |
| 10 |
object or prototype. |
| 11 |
|
| 12 |
But this also causes unnecessary churn. Sometimes there will be a structure that we just |
| 13 |
haven't really done anything with recently and so it appears dead. The approach we use |
| 14 |
elsewhere in our type inference is that the type that the code uses is general enough to |
| 15 |
handle every past execution. Having the GC clear code when some Structure it uses dies means |
| 16 |
that we forget that the code used that Structure. We'll either assume that the code is more |
| 17 |
monomorphic than it really is (because after GC we patch in some other structure but not the |
| 18 |
deleted one, so it looks like we only ever saw the new structure), or we'll assume that it's |
| 19 |
crazier than it really is (because we'll remember that there had been some structure that |
| 20 |
caused deletion, so we'll assume that deletions might happen in the future, so we'll use a |
| 21 |
fully dynamic IC). |
| 22 |
|
| 23 |
This change introduces a more nuanced policy a more nuanced policy: if it's cheap to mark a |
| 24 |
dead Structure then we should mark it just so that all of the code that refers to it |
| 25 |
remembers that there had been this exact Structure in the past. If the code often goes |
| 26 |
through different Structures then we already have great mechanisms to realize that the code |
| 27 |
is nutty (namely, the PolymorphicAccess size limit). But if the code just does this a |
| 28 |
handful of times then remembering this old Structure is probably net good: |
| 29 |
|
| 30 |
- It obeys the "handle all past executions" law. |
| 31 |
- It preserves the history of the property access, allowing a precise measure of its past |
| 32 |
polymorphism. |
| 33 |
- It makes the code ready to run fast if the user decides to use that Structure again. |
| 34 |
Marking the Structure means it will stay in whatever property transition tables it was in, |
| 35 |
so if the program does the same thing it did in the past, it will get this old Structure. |
| 36 |
|
| 37 |
It looks like this is a progression in gbemu and it makes gbemu perform more |
| 38 |
deterministically. Also, it seems that this makes JetStream run faster. |
| 39 |
|
| 40 |
Over five in-browser runs of JetStream, here's what we see before and after: |
| 41 |
|
| 42 |
Geometric Mean: |
| 43 |
Before After |
| 44 |
229.23 +- 8.2523 230.70 +- 12.888 |
| 45 |
232.91 +- 15.638 239.04 +- 13.766 |
| 46 |
234.79 +- 12.760 236.32 +- 15.562 |
| 47 |
236.20 +- 23.125 242.02 +- 3.3865 |
| 48 |
237.22 +- 2.1929 237.23 +- 17.664 |
| 49 |
|
| 50 |
Just gbemu: |
| 51 |
Before After |
| 52 |
541.0 +- 135.8 481.7 +- 143.4 |
| 53 |
518.9 +- 15.65 508.1 +- 136.3 |
| 54 |
362.5 +- 0.8884 489.7 +- 101.4 |
| 55 |
470.7 +- 313.3 530.7 +- 11.49 |
| 56 |
418.7 +- 180.6 537.2 +- 6.514 |
| 57 |
|
| 58 |
Notice that there is plenty of noise before and after, but the noise is now far less severe. |
| 59 |
After this change I did not see any runs like "470.7 +- 313.3" where the size of the |
| 60 |
confidence interval (313.3 * 2) is greater than the score (470.7). Also, notice that the |
| 61 |
least noisy run before the change also got a lower score than we ever observed after the |
| 62 |
change (36.5 +- 0.8884). The noise, and these occasional very low scores, are due to a |
| 63 |
pathology where the GC would reset some stubs at an unfortunate time during profiling, |
| 64 |
causing the optimizing compiler to make many poor decisions. That pathology doesn't exist |
| 65 |
anymore. |
| 66 |
|
| 67 |
On the other hand, prior to this change it was possible for gbemu to sometimes run sooooper |
| 68 |
fast because the GC would cause the profiler to forget gbemu's behavior on the first tick |
| 69 |
and focus only on its behavior in subsequent ticks. So, in steady state, we'd optimize gbemu |
| 70 |
for its later behavior rather than a combination of its early behavior and later behavior. |
| 71 |
We rarely got lucky this way, so it's not fair to view this quirk as a feature. |
| 72 |
|
| 73 |
* bytecode/CodeBlock.cpp: |
| 74 |
(JSC::CodeBlock::propagateTransitions): |
| 75 |
* bytecode/PolymorphicAccess.cpp: |
| 76 |
(JSC::AccessCase::visitWeak): |
| 77 |
(JSC::AccessCase::propagateTransitions): |
| 78 |
(JSC::AccessCase::generateWithGuard): |
| 79 |
(JSC::PolymorphicAccess::visitWeak): |
| 80 |
(JSC::PolymorphicAccess::propagateTransitions): |
| 81 |
(JSC::PolymorphicAccess::dump): |
| 82 |
* bytecode/PolymorphicAccess.h: |
| 83 |
* bytecode/StructureStubInfo.cpp: |
| 84 |
(JSC::StructureStubInfo::visitWeakReferences): |
| 85 |
(JSC::StructureStubInfo::propagateTransitions): |
| 86 |
(JSC::StructureStubInfo::containsPC): |
| 87 |
* bytecode/StructureStubInfo.h: |
| 88 |
(JSC::StructureStubInfo::considerCaching): |
| 89 |
* runtime/Structure.cpp: |
| 90 |
(JSC::Structure::visitChildren): |
| 91 |
(JSC::Structure::isCheapDuringGC): |
| 92 |
(JSC::Structure::markIfCheap): |
| 93 |
(JSC::Structure::prototypeChainMayInterceptStoreTo): |
| 94 |
* runtime/Structure.h: |
| 95 |
|
| 1 |
2016-05-03 Michael Saboff <msaboff@apple.com> |
96 |
2016-05-03 Michael Saboff <msaboff@apple.com> |
| 2 |
|
97 |
|
| 3 |
Crash: Array.prototype.slice() and .splice() can call fastSlice() after an array is truncated |
98 |
Crash: Array.prototype.slice() and .splice() can call fastSlice() after an array is truncated |