2008-06-29 Cameron Zwarich <cwzwarich@uwaterloo.ca>
[WebKit-https.git] / JavaScriptCore / VM / Opcode.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "Opcode.h"
32
33 #include <stdlib.h>
34
35 using namespace std;
36
37 namespace KJS {
38
39 #if DUMP_OPCODE_STATS
40
41 long long OpcodeStats::opcodeCounts[numOpcodeIDs];
42 long long OpcodeStats::opcodePairCounts[numOpcodeIDs][numOpcodeIDs];
43 int OpcodeStats::lastOpcode = -1;
44
45 static OpcodeStats logger;
46
47 static const char* opcodeNames[] = {
48     "load        ",
49     "new_object  ",
50     "new_array   ",
51     "new_regexp  ",
52     "mov         ",
53     
54     "not         ",
55     "eq          ",
56     "neq         ",
57     "stricteq    ",
58     "nstricteq   ",
59     "less        ",
60     "lesseq      ",
61     
62     "pre_inc     ",
63     "pre_dec     ",
64     "post_inc    ",
65     "post_dec    ",
66     "to_jsnumber ",
67     "negate      ",
68     "add         ",
69     "mul         ",
70     "div         ",
71     "mod         ",
72     "sub         ",
73     
74     "lshift      ",
75     "rshift      ",
76     "urshift     ",
77     "bitand      ",
78     "bitxor      ",
79     "bitor       ",
80     "bitnot      ",
81     
82     "instanceof  ",
83     "typeof      ",
84     "in          ",
85
86     "resolve     ",
87     "resolve_skip",
88     "get_scoped_var",
89     "put_scoped_var",
90     "resolve_base",
91     "resolve_with_base",
92     "resolve_func",
93     "get_by_id   ",
94     "put_by_id   ",
95     "del_by_id   ",
96     "get_by_val  ",
97     "put_by_val  ",
98     "del_by_val  ",
99     "put_by_index",
100     "put_getter  ",
101     "put_setter  ",
102
103     "jmp         ",
104     "jtrue       ",
105     "jfalse      ",
106     "jless       ",
107     "jnless      ",
108     "jmp_scopes  ",
109     "loop        ",
110     "loop_if_true",
111     "loop_if_less",
112
113     "new_func    ",
114     "new_func_exp",
115     "call        ",
116     "call_eval   ",
117     "ret         ",
118
119     "construct   ",
120
121     "get_pnames  ",
122     "next_pname  ",
123
124     "push_scope  ",
125     "pop_scope   ",
126
127     "catch       ",
128     "throw       ",
129     "new_error   ",
130
131     "jsr         ",
132     "sret        ",
133
134     "debug       ",
135
136     "end         "
137 };
138
139 OpcodeStats::OpcodeStats()
140 {
141     for (int i = 0; i < numOpcodeIDs; ++i)
142         opcodeCounts[i] = 0;
143     
144     for (int i = 0; i < numOpcodeIDs; ++i)
145         for (int j = 0; j < numOpcodeIDs; ++j)
146             opcodePairCounts[i][j] = 0;
147 }
148
149 static int compareOpcodeIndices(const void* left, const void* right)
150 {
151     long long leftValue = OpcodeStats::opcodeCounts[*(int*) left];
152     long long rightValue = OpcodeStats::opcodeCounts[*(int*) right];
153     
154     if (leftValue < rightValue)
155         return 1;
156     else if (leftValue > rightValue)
157         return -1;
158     else
159         return 0;
160 }
161
162 static int compareOpcodePairIndices(const void* left, const void* right)
163 {
164     pair<int, int> leftPair = *(pair<int, int>*) left;
165     long long leftValue = OpcodeStats::opcodePairCounts[leftPair.first][leftPair.second];
166     pair<int, int> rightPair = *(pair<int, int>*) right;
167     long long rightValue = OpcodeStats::opcodePairCounts[rightPair.first][rightPair.second];
168     
169     if (leftValue < rightValue)
170         return 1;
171     else if (leftValue > rightValue)
172         return -1;
173     else
174         return 0;
175 }
176
177 OpcodeStats::~OpcodeStats()
178 {
179     long long totalInstructions = 0;
180     for (int i = 0; i < numOpcodeIDs; ++i)
181         totalInstructions += opcodeCounts[i];
182     
183     long long totalInstructionPairs = 0;
184     for (int i = 0; i < numOpcodeIDs; ++i)
185         for (int j = 0; j < numOpcodeIDs; ++j)
186             totalInstructionPairs += opcodePairCounts[i][j];
187
188     int sortedIndices[numOpcodeIDs];    
189     for (int i = 0; i < numOpcodeIDs; ++i)
190         sortedIndices[i] = i;
191     mergesort(sortedIndices, numOpcodeIDs, sizeof(int), compareOpcodeIndices);
192     
193     pair<int, int> sortedPairIndices[numOpcodeIDs * numOpcodeIDs];
194     pair<int, int>* currentPairIndex = sortedPairIndices;
195     for (int i = 0; i < numOpcodeIDs; ++i)
196         for (int j = 0; j < numOpcodeIDs; ++j)
197             *(currentPairIndex++) = make_pair(i, j);
198     mergesort(sortedPairIndices, numOpcodeIDs * numOpcodeIDs, sizeof(pair<int, int>), compareOpcodePairIndices);
199     
200     printf("\nExecuted opcode statistics\n"); 
201     
202     printf("Total instructions executed: %lld\n\n", totalInstructions);
203
204     printf("All opcodes by frequency:\n\n");
205
206     for (int i = 0; i < numOpcodeIDs; ++i) {
207         int index = sortedIndices[i];
208         printf("%s: %lld - %.2f%%\n", opcodeNames[index], opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0);    
209     }
210     
211     printf("\n");
212     printf("2-opcode sequences by frequency: %lld\n\n", totalInstructions);
213     
214     for (int i = 0; i < numOpcodeIDs * numOpcodeIDs; ++i) {
215         pair<int, int> indexPair = sortedPairIndices[i];
216         long long count = opcodePairCounts[indexPair.first][indexPair.second];
217         
218         if (!count)
219             break;
220         
221         printf("%s %s: %lld %.2f%%\n", opcodeNames[indexPair.first], opcodeNames[indexPair.second], count, ((double) count) / ((double) totalInstructionPairs) * 100.0);
222     }
223     
224     printf("\n");
225     printf("Most common opcodes and sequences:\n");
226
227     for (int i = 0; i < numOpcodeIDs; ++i) {
228         int index = sortedIndices[i];
229         long long opcodeCount = opcodeCounts[index];
230         double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions);
231         if (opcodeProportion < 0.0001)
232             break;
233         printf("\n%s: %lld - %.2f%%\n", opcodeNames[index], opcodeCount, opcodeProportion * 100.0);
234
235         for (int j = 0; j < numOpcodeIDs * numOpcodeIDs; ++j) {
236             pair<int, int> indexPair = sortedPairIndices[j];
237             long long pairCount = opcodePairCounts[indexPair.first][indexPair.second];
238             double pairProportion = ((double) pairCount) / ((double) totalInstructionPairs);
239         
240             if (!pairCount || pairProportion < 0.0001 || pairProportion < opcodeProportion / 100)
241                 break;
242
243             if (indexPair.first != index && indexPair.second != index)
244                 continue;
245
246             printf("    %s %s: %lld - %.2f%%\n", opcodeNames[indexPair.first], opcodeNames[indexPair.second], pairCount, pairProportion * 100.0);
247         }
248         
249     }
250     printf("\n");
251 }
252
253 void OpcodeStats::recordInstruction(int opcode)
254 {
255     opcodeCounts[opcode]++;
256     
257     if (lastOpcode != -1)
258         opcodePairCounts[lastOpcode][opcode]++;
259     
260     lastOpcode = opcode;
261 }
262
263 void OpcodeStats::resetLastInstruction()
264 {
265     lastOpcode = -1;
266 }
267
268 #endif
269
270 } // namespace WTF