source: webkit/trunk/JavaScriptCore/VM/CodeBlock.cpp@ 36695

Last change on this file since 36695 was 36695, checked in by [email protected], 17 years ago

Improve peformance of local variable initialisation.

Reviewed by Maciej Stachowiak

Pull local and constant initialisation out of slideRegisterWindowForCall
and into its own opcode. This allows the JIT to generate the initialisation
code for a function directly into the instruction stream and so avoids a few
branches on function entry.

Results a 1% progression in SunSpider, particularly in a number of the bitop
tests where the called functions are very fast.

File size: 40.5 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
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 "CodeBlock.h"
32
33#include "JSValue.h"
34#include "Machine.h"
35#include "debugger.h"
36#include <stdio.h>
37#include <wtf/StringExtras.h>
38
39namespace JSC {
40
41#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
42
43static UString escapeQuotes(const UString& str)
44{
45 UString result = str;
46 int pos = 0;
47 while ((pos = result.find('\"', pos)) >= 0) {
48 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
49 pos += 4;
50 }
51 return result;
52}
53
54static UString valueToSourceString(ExecState* exec, JSValue* val)
55{
56 if (val->isString()) {
57 UString result("\"");
58 result += escapeQuotes(val->toString(exec)) + "\"";
59 return result;
60 }
61
62 return val->toString(exec);
63}
64
65static CString registerName(int r)
66{
67 if (r < 0)
68 return (UString("lr") + UString::from(-r)).UTF8String();
69
70 if (r == missingThisObjectMarker())
71 return "<null>";
72
73 return (UString("tr") + UString::from(r)).UTF8String();
74}
75
76static CString constantName(ExecState* exec, int k, JSValue* value)
77{
78 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
79}
80
81static CString idName(int id0, const Identifier& ident)
82{
83 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
84}
85
86static UString regexpToSourceString(RegExp* regExp)
87{
88 UString pattern = UString("/") + regExp->pattern() + "/";
89 if (regExp->global())
90 pattern += "g";
91 if (regExp->ignoreCase())
92 pattern += "i";
93 if (regExp->multiline())
94 pattern += "m";
95
96 return pattern;
97}
98
99static CString regexpName(int re, RegExp* regexp)
100{
101 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
102}
103
104static UString pointerToSourceString(void* p)
105{
106 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
107 snprintf(buffer, sizeof(buffer), "%p", p);
108 return buffer;
109}
110
111NEVER_INLINE static const char* debugHookName(int debugHookID)
112{
113 switch (static_cast<DebugHookID>(debugHookID)) {
114 case DidEnterCallFrame:
115 return "didEnterCallFrame";
116 case WillLeaveCallFrame:
117 return "willLeaveCallFrame";
118 case WillExecuteStatement:
119 return "willExecuteStatement";
120 case WillExecuteProgram:
121 return "willExecuteProgram";
122 case DidExecuteProgram:
123 return "didExecuteProgram";
124 case DidReachBreakpoint:
125 return "didReachBreakpoint";
126 }
127
128 ASSERT_NOT_REACHED();
129 return "";
130}
131
132static int jumpTarget(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
133{
134 return it - begin + offset;
135}
136
137static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
138{
139 int r0 = (++it)->u.operand;
140 int r1 = (++it)->u.operand;
141
142 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
143}
144
145static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
146{
147 int r0 = (++it)->u.operand;
148 int r1 = (++it)->u.operand;
149 int r2 = (++it)->u.operand;
150 printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
151}
152
153static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
154{
155 int r0 = (++it)->u.operand;
156 int offset = (++it)->u.operand;
157 printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, jumpTarget(begin, it, offset));
158}
159
160static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
161{
162 int r0 = (++it)->u.operand;
163 int r1 = (++it)->u.operand;
164 int id0 = (++it)->u.operand;
165 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
166 it += 4;
167}
168
169static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
170{
171 int r0 = (++it)->u.operand;
172 int id0 = (++it)->u.operand;
173 int r1 = (++it)->u.operand;
174 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
175 it += 4;
176}
177
178void CodeBlock::printStructureID(const char* name, const Instruction* vPC, int operand) const
179{
180 unsigned instructionOffset = vPC - instructions.begin();
181 printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structureID).UTF8String().c_str());
182}
183
184void CodeBlock::printStructureIDs(const Instruction* vPC) const
185{
186 Machine* machine = globalData->machine;
187 unsigned instructionOffset = vPC - instructions.begin();
188
189 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id)) {
190 printStructureID("get_by_id", vPC, 4);
191 return;
192 }
193 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
194 printStructureID("get_by_id_self", vPC, 4);
195 return;
196 }
197 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
198 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str());
199 return;
200 }
201 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
202 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_new", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureIDChain).UTF8String().c_str());
203 return;
204 }
205 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
206 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureIDChain).UTF8String().c_str());
207 return;
208 }
209 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id)) {
210 printStructureID("put_by_id", vPC, 4);
211 return;
212 }
213 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
214 printStructureID("put_by_id_replace", vPC, 4);
215 return;
216 }
217 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
218 printStructureID("resolve_global", vPC, 4);
219 return;
220 }
221
222 // These instructions doesn't ref StructureIDs.
223 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
224}
225
226void CodeBlock::dump(ExecState* exec) const
227{
228 Vector<Instruction>::const_iterator begin = instructions.begin();
229 Vector<Instruction>::const_iterator end = instructions.end();
230
231 size_t instructionCount = 0;
232 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
233 if (exec->machine()->isOpcode(it->u.opcode))
234 ++instructionCount;
235
236 printf("%lu instructions; %lu bytes at %p; %d locals (%d parameters); %d temporaries\n\n",
237 static_cast<unsigned long>(instructionCount),
238 static_cast<unsigned long>(instructions.size() * sizeof(Instruction)),
239 this, numLocals, numParameters, numTemporaries);
240
241 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
242 dump(exec, begin, it);
243
244 if (identifiers.size()) {
245 printf("\nIdentifiers:\n");
246 size_t i = 0;
247 do {
248 printf(" id%u = %s\n", static_cast<unsigned>(i), identifiers[i].ascii());
249 ++i;
250 } while (i != identifiers.size());
251 }
252
253 if (constantRegisters.size()) {
254 printf("\nConstants:\n");
255 size_t i = 0;
256 do {
257 printf(" tr%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
258 ++i;
259 } while (i < constantRegisters.size());
260 }
261
262 if (unexpectedConstants.size()) {
263 printf("\nUnexpected Constants:\n");
264 size_t i = 0;
265 do {
266 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, unexpectedConstants[i]).ascii());
267 ++i;
268 } while (i < unexpectedConstants.size());
269 }
270
271 if (regexps.size()) {
272 printf("\nRegExps:\n");
273 size_t i = 0;
274 do {
275 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(regexps[i].get()).ascii());
276 ++i;
277 } while (i < regexps.size());
278 }
279
280 if (structureIDInstructions.size()) {
281 printf("\nStructureIDs:\n");
282 size_t i = 0;
283 do {
284 printStructureIDs(&instructions[structureIDInstructions[i].opcodeIndex]);
285 ++i;
286 } while (i < structureIDInstructions.size());
287 }
288
289 if (exceptionHandlers.size()) {
290 printf("\nException Handlers:\n");
291 unsigned i = 0;
292 do {
293 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
294 ++i;
295 } while (i < exceptionHandlers.size());
296 }
297
298 if (immediateSwitchJumpTables.size()) {
299 printf("Immediate Switch Jump Tables:\n");
300 unsigned i = 0;
301 do {
302 printf(" %1d = {\n", i);
303 int entry = 0;
304 Vector<int32_t>::const_iterator end = immediateSwitchJumpTables[i].branchOffsets.end();
305 for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
306 if (!*iter)
307 continue;
308 printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
309 }
310 printf(" }\n");
311 ++i;
312 } while (i < immediateSwitchJumpTables.size());
313 }
314
315 if (characterSwitchJumpTables.size()) {
316 printf("\nCharacter Switch Jump Tables:\n");
317 unsigned i = 0;
318 do {
319 printf(" %1d = {\n", i);
320 int entry = 0;
321 Vector<int32_t>::const_iterator end = characterSwitchJumpTables[i].branchOffsets.end();
322 for (Vector<int32_t>::const_iterator iter = characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
323 if (!*iter)
324 continue;
325 ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
326 UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
327 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
328 }
329 printf(" }\n");
330 ++i;
331 } while (i < characterSwitchJumpTables.size());
332 }
333
334 if (stringSwitchJumpTables.size()) {
335 printf("\nString Switch Jump Tables:\n");
336 unsigned i = 0;
337 do {
338 printf(" %1d = {\n", i);
339 StringJumpTable::StringOffsetTable::const_iterator end = stringSwitchJumpTables[i].offsetTable.end();
340 for (StringJumpTable::StringOffsetTable::const_iterator iter = stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
341 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
342 printf(" }\n");
343 ++i;
344 } while (i < stringSwitchJumpTables.size());
345 }
346
347 printf("\n");
348}
349
350void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
351{
352 int location = it - begin;
353 switch (exec->machine()->getOpcodeID(it->u.opcode)) {
354 case op_initialise_locals: {
355 printf("[%4d] initialise_locals\n", location);
356 break;
357 }
358 case op_unexpected_load: {
359 int r0 = (++it)->u.operand;
360 int k0 = (++it)->u.operand;
361 printf("[%4d] unexpected_load\t %s, %s\n", location, registerName(r0).c_str(), constantName(exec, k0, unexpectedConstants[k0]).c_str());
362 break;
363 }
364 case op_new_object: {
365 int r0 = (++it)->u.operand;
366 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
367 break;
368 }
369 case op_new_array: {
370 int dst = (++it)->u.operand;
371 int argv = (++it)->u.operand;
372 int argc = (++it)->u.operand;
373 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
374 break;
375 }
376 case op_new_regexp: {
377 int r0 = (++it)->u.operand;
378 int re0 = (++it)->u.operand;
379 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexps[re0].get()).c_str());
380 break;
381 }
382 case op_mov: {
383 int r0 = (++it)->u.operand;
384 int r1 = (++it)->u.operand;
385 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
386 break;
387 }
388 case op_not: {
389 printUnaryOp(location, it, "not");
390 break;
391 }
392 case op_eq: {
393 printBinaryOp(location, it, "eq");
394 break;
395 }
396 case op_eq_null: {
397 printUnaryOp(location, it, "eq_null");
398 break;
399 }
400 case op_neq: {
401 printBinaryOp(location, it, "neq");
402 break;
403 }
404 case op_neq_null: {
405 printUnaryOp(location, it, "neq_null");
406 break;
407 }
408 case op_stricteq: {
409 printBinaryOp(location, it, "stricteq");
410 break;
411 }
412 case op_nstricteq: {
413 printBinaryOp(location, it, "nstricteq");
414 break;
415 }
416 case op_less: {
417 printBinaryOp(location, it, "less");
418 break;
419 }
420 case op_lesseq: {
421 printBinaryOp(location, it, "lesseq");
422 break;
423 }
424 case op_pre_inc: {
425 int r0 = (++it)->u.operand;
426 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
427 break;
428 }
429 case op_pre_dec: {
430 int r0 = (++it)->u.operand;
431 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
432 break;
433 }
434 case op_post_inc: {
435 printUnaryOp(location, it, "post_inc");
436 break;
437 }
438 case op_post_dec: {
439 printUnaryOp(location, it, "post_dec");
440 break;
441 }
442 case op_to_jsnumber: {
443 printUnaryOp(location, it, "to_jsnumber");
444 break;
445 }
446 case op_negate: {
447 printUnaryOp(location, it, "negate");
448 break;
449 }
450 case op_add: {
451 printBinaryOp(location, it, "add");
452 break;
453 }
454 case op_mul: {
455 printBinaryOp(location, it, "mul");
456 break;
457 }
458 case op_div: {
459 printBinaryOp(location, it, "div");
460 break;
461 }
462 case op_mod: {
463 printBinaryOp(location, it, "mod");
464 break;
465 }
466 case op_sub: {
467 printBinaryOp(location, it, "sub");
468 break;
469 }
470 case op_lshift: {
471 printBinaryOp(location, it, "lshift");
472 break;
473 }
474 case op_rshift: {
475 printBinaryOp(location, it, "rshift");
476 break;
477 }
478 case op_urshift: {
479 printBinaryOp(location, it, "urshift");
480 break;
481 }
482 case op_bitand: {
483 printBinaryOp(location, it, "bitand");
484 break;
485 }
486 case op_bitxor: {
487 printBinaryOp(location, it, "bitxor");
488 break;
489 }
490 case op_bitor: {
491 printBinaryOp(location, it, "bitor");
492 break;
493 }
494 case op_bitnot: {
495 printUnaryOp(location, it, "bitnot");
496 break;
497 }
498 case op_instanceof: {
499 int r0 = (++it)->u.operand;
500 int r1 = (++it)->u.operand;
501 int r2 = (++it)->u.operand;
502 int r3 = (++it)->u.operand;
503 printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str());
504 break;
505 }
506 case op_typeof: {
507 printUnaryOp(location, it, "typeof");
508 break;
509 }
510 case op_is_undefined: {
511 printUnaryOp(location, it, "is_undefined");
512 break;
513 }
514 case op_is_boolean: {
515 printUnaryOp(location, it, "is_boolean");
516 break;
517 }
518 case op_is_number: {
519 printUnaryOp(location, it, "is_number");
520 break;
521 }
522 case op_is_string: {
523 printUnaryOp(location, it, "is_string");
524 break;
525 }
526 case op_is_object: {
527 printUnaryOp(location, it, "is_object");
528 break;
529 }
530 case op_is_function: {
531 printUnaryOp(location, it, "is_function");
532 break;
533 }
534 case op_in: {
535 printBinaryOp(location, it, "in");
536 break;
537 }
538 case op_resolve: {
539 int r0 = (++it)->u.operand;
540 int id0 = (++it)->u.operand;
541 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
542 break;
543 }
544 case op_resolve_skip: {
545 int r0 = (++it)->u.operand;
546 int id0 = (++it)->u.operand;
547 int skipLevels = (++it)->u.operand;
548 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), skipLevels);
549 break;
550 }
551 case op_resolve_global: {
552 int r0 = (++it)->u.operand;
553 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
554 int id0 = (++it)->u.operand;
555 printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, identifiers[id0]).c_str());
556 it += 2;
557 break;
558 }
559 case op_get_scoped_var: {
560 int r0 = (++it)->u.operand;
561 int index = (++it)->u.operand;
562 int skipLevels = (++it)->u.operand;
563 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
564 break;
565 }
566 case op_put_scoped_var: {
567 int index = (++it)->u.operand;
568 int skipLevels = (++it)->u.operand;
569 int r0 = (++it)->u.operand;
570 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
571 break;
572 }
573 case op_get_global_var: {
574 int r0 = (++it)->u.operand;
575 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
576 int index = (++it)->u.operand;
577 printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
578 break;
579 }
580 case op_put_global_var: {
581 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
582 int index = (++it)->u.operand;
583 int r0 = (++it)->u.operand;
584 printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
585 break;
586 }
587 case op_resolve_base: {
588 int r0 = (++it)->u.operand;
589 int id0 = (++it)->u.operand;
590 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
591 break;
592 }
593 case op_resolve_with_base: {
594 int r0 = (++it)->u.operand;
595 int r1 = (++it)->u.operand;
596 int id0 = (++it)->u.operand;
597 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
598 break;
599 }
600 case op_resolve_func: {
601 int r0 = (++it)->u.operand;
602 int r1 = (++it)->u.operand;
603 int id0 = (++it)->u.operand;
604 printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
605 break;
606 }
607 case op_get_by_id: {
608 printGetByIdOp(location, it, identifiers, "get_by_id");
609 break;
610 }
611 case op_get_by_id_self: {
612 printGetByIdOp(location, it, identifiers, "get_by_id_self");
613 break;
614 }
615 case op_get_by_id_proto: {
616 printGetByIdOp(location, it, identifiers, "get_by_id_proto");
617 break;
618 }
619 case op_get_by_id_chain: {
620 printGetByIdOp(location, it, identifiers, "get_by_id_chain");
621 break;
622 }
623 case op_get_by_id_generic: {
624 printGetByIdOp(location, it, identifiers, "get_by_id_generic");
625 break;
626 }
627 case op_get_array_length: {
628 printGetByIdOp(location, it, identifiers, "get_array_length");
629 break;
630 }
631 case op_get_string_length: {
632 printGetByIdOp(location, it, identifiers, "get_string_length");
633 break;
634 }
635 case op_put_by_id: {
636 printPutByIdOp(location, it, identifiers, "put_by_id");
637 break;
638 }
639 case op_put_by_id_replace: {
640 printPutByIdOp(location, it, identifiers, "put_by_id_replace");
641 break;
642 }
643 case op_put_by_id_transition: {
644 printPutByIdOp(location, it, identifiers, "put_by_id_transition");
645 break;
646 }
647 case op_put_by_id_generic: {
648 printPutByIdOp(location, it, identifiers, "put_by_id_generic");
649 break;
650 }
651 case op_put_getter: {
652 int r0 = (++it)->u.operand;
653 int id0 = (++it)->u.operand;
654 int r1 = (++it)->u.operand;
655 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
656 break;
657 }
658 case op_put_setter: {
659 int r0 = (++it)->u.operand;
660 int id0 = (++it)->u.operand;
661 int r1 = (++it)->u.operand;
662 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
663 break;
664 }
665 case op_del_by_id: {
666 int r0 = (++it)->u.operand;
667 int r1 = (++it)->u.operand;
668 int id0 = (++it)->u.operand;
669 printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
670 break;
671 }
672 case op_get_by_val: {
673 int r0 = (++it)->u.operand;
674 int r1 = (++it)->u.operand;
675 int r2 = (++it)->u.operand;
676 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
677 break;
678 }
679 case op_put_by_val: {
680 int r0 = (++it)->u.operand;
681 int r1 = (++it)->u.operand;
682 int r2 = (++it)->u.operand;
683 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
684 break;
685 }
686 case op_del_by_val: {
687 int r0 = (++it)->u.operand;
688 int r1 = (++it)->u.operand;
689 int r2 = (++it)->u.operand;
690 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
691 break;
692 }
693 case op_put_by_index: {
694 int r0 = (++it)->u.operand;
695 unsigned n0 = (++it)->u.operand;
696 int r1 = (++it)->u.operand;
697 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
698 break;
699 }
700 case op_jmp: {
701 int offset = (++it)->u.operand;
702 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
703 break;
704 }
705 case op_loop: {
706 int offset = (++it)->u.operand;
707 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
708 break;
709 }
710 case op_jtrue: {
711 printConditionalJump(begin, it, location, "jtrue");
712 break;
713 }
714 case op_loop_if_true: {
715 printConditionalJump(begin, it, location, "loop_if_true");
716 break;
717 }
718 case op_jfalse: {
719 printConditionalJump(begin, it, location, "jfalse");
720 break;
721 }
722 case op_jnless: {
723 int r0 = (++it)->u.operand;
724 int r1 = (++it)->u.operand;
725 int offset = (++it)->u.operand;
726 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
727 break;
728 }
729 case op_loop_if_less: {
730 int r0 = (++it)->u.operand;
731 int r1 = (++it)->u.operand;
732 int offset = (++it)->u.operand;
733 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
734 break;
735 }
736 case op_loop_if_lesseq: {
737 int r0 = (++it)->u.operand;
738 int r1 = (++it)->u.operand;
739 int offset = (++it)->u.operand;
740 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
741 break;
742 }
743 case op_switch_imm: {
744 int tableIndex = (++it)->u.operand;
745 int defaultTarget = (++it)->u.operand;
746 int scrutineeRegister = (++it)->u.operand;
747 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
748 break;
749 }
750 case op_switch_char: {
751 int tableIndex = (++it)->u.operand;
752 int defaultTarget = (++it)->u.operand;
753 int scrutineeRegister = (++it)->u.operand;
754 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
755 break;
756 }
757 case op_switch_string: {
758 int tableIndex = (++it)->u.operand;
759 int defaultTarget = (++it)->u.operand;
760 int scrutineeRegister = (++it)->u.operand;
761 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
762 break;
763 }
764 case op_new_func: {
765 int r0 = (++it)->u.operand;
766 int f0 = (++it)->u.operand;
767 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
768 break;
769 }
770 case op_new_func_exp: {
771 int r0 = (++it)->u.operand;
772 int f0 = (++it)->u.operand;
773 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
774 break;
775 }
776 case op_call: {
777 int r0 = (++it)->u.operand;
778 int r1 = (++it)->u.operand;
779 int r2 = (++it)->u.operand;
780 int tempCount = (++it)->u.operand;
781 int argCount = (++it)->u.operand;
782 printf("[%4d] call\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
783 break;
784 }
785 case op_call_eval: {
786 int r0 = (++it)->u.operand;
787 int r1 = (++it)->u.operand;
788 int r2 = (++it)->u.operand;
789 int tempCount = (++it)->u.operand;
790 int argCount = (++it)->u.operand;
791 printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
792 break;
793 }
794 case op_ret: {
795 int r0 = (++it)->u.operand;
796 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
797 break;
798 }
799 case op_construct: {
800 int r0 = (++it)->u.operand;
801 int r1 = (++it)->u.operand;
802 int r2 = (++it)->u.operand;
803 int tempCount = (++it)->u.operand;
804 int argCount = (++it)->u.operand;
805 printf("[%4d] construct\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
806 break;
807 }
808 case op_construct_verify: {
809 int r0 = (++it)->u.operand;
810 int r1 = (++it)->u.operand;
811 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
812 break;
813 }
814 case op_get_pnames: {
815 int r0 = (++it)->u.operand;
816 int r1 = (++it)->u.operand;
817 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
818 break;
819 }
820 case op_next_pname: {
821 int dest = (++it)->u.operand;
822 int iter = (++it)->u.operand;
823 int offset = (++it)->u.operand;
824 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, jumpTarget(begin, it, offset));
825 break;
826 }
827 case op_push_scope: {
828 int r0 = (++it)->u.operand;
829 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
830 break;
831 }
832 case op_pop_scope: {
833 printf("[%4d] pop_scope\n", location);
834 break;
835 }
836 case op_push_new_scope: {
837 int r0 = (++it)->u.operand;
838 int id0 = (++it)->u.operand;
839 int r1 = (++it)->u.operand;
840 printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
841 break;
842 }
843 case op_jmp_scopes: {
844 int scopeDelta = (++it)->u.operand;
845 int offset = (++it)->u.operand;
846 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, jumpTarget(begin, it, offset));
847 break;
848 }
849 case op_catch: {
850 int r0 = (++it)->u.operand;
851 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
852 break;
853 }
854 case op_throw: {
855 int r0 = (++it)->u.operand;
856 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
857 break;
858 }
859 case op_new_error: {
860 int r0 = (++it)->u.operand;
861 int errorType = (++it)->u.operand;
862 int k0 = (++it)->u.operand;
863 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstants[k0]).c_str());
864 break;
865 }
866 case op_jsr: {
867 int retAddrDst = (++it)->u.operand;
868 int offset = (++it)->u.operand;
869 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, jumpTarget(begin, it, offset));
870 break;
871 }
872 case op_sret: {
873 int retAddrSrc = (++it)->u.operand;
874 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
875 break;
876 }
877 case op_debug: {
878 int debugHookID = (++it)->u.operand;
879 int firstLine = (++it)->u.operand;
880 int lastLine = (++it)->u.operand;
881 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
882 break;
883 }
884 case op_end: {
885 int r0 = (++it)->u.operand;
886 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
887 break;
888 }
889 default: {
890 ASSERT_NOT_REACHED();
891 break;
892 }
893 }
894}
895
896#endif // !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
897
898CodeBlock::~CodeBlock()
899{
900 size_t size = structureIDInstructions.size();
901 for (size_t i = 0; i < size; ++i) {
902 derefStructureIDs(&instructions[structureIDInstructions[i].opcodeIndex]);
903 if (structureIDInstructions[i].stubRoutine)
904 fastFree(structureIDInstructions[i].stubRoutine);
905 }
906#if ENABLE(CTI)
907 if (ctiCode)
908 fastFree(ctiCode);
909#endif
910}
911
912void CodeBlock::derefStructureIDs(Instruction* vPC) const
913{
914 Machine* machine = globalData->machine;
915
916 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
917 vPC[4].u.structureID->deref();
918 return;
919 }
920 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
921 vPC[4].u.structureID->deref();
922 vPC[5].u.structureID->deref();
923 return;
924 }
925 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
926 vPC[4].u.structureID->deref();
927 vPC[5].u.structureIDChain->deref();
928 return;
929 }
930 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
931 vPC[4].u.structureID->deref();
932 vPC[5].u.structureID->deref();
933 vPC[6].u.structureIDChain->deref();
934 return;
935 }
936 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
937 vPC[4].u.structureID->deref();
938 return;
939 }
940 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
941 if(vPC[4].u.structureID)
942 vPC[4].u.structureID->deref();
943 return;
944 }
945
946 // These instructions don't ref their StructureIDs.
947 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_get_array_length) || vPC[0].u.opcode == machine->getOpcode(op_get_string_length));
948}
949
950void CodeBlock::refStructureIDs(Instruction* vPC) const
951{
952 Machine* machine = globalData->machine;
953
954 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
955 vPC[4].u.structureID->ref();
956 return;
957 }
958 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
959 vPC[4].u.structureID->ref();
960 vPC[5].u.structureID->ref();
961 return;
962 }
963 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
964 vPC[4].u.structureID->ref();
965 vPC[5].u.structureIDChain->ref();
966 return;
967 }
968 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
969 vPC[4].u.structureID->ref();
970 vPC[5].u.structureID->ref();
971 vPC[6].u.structureIDChain->ref();
972 return;
973 }
974 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
975 vPC[4].u.structureID->ref();
976 return;
977 }
978
979 // These instructions don't ref their StructureIDs.
980 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
981}
982
983void CodeBlock::mark()
984{
985 for (size_t i = 0; i < constantRegisters.size(); ++i)
986 if (!constantRegisters[i].marked())
987 constantRegisters[i].mark();
988
989 for (size_t i = 0; i < unexpectedConstants.size(); ++i)
990 if (!unexpectedConstants[i]->marked())
991 unexpectedConstants[i]->mark();
992
993 for (size_t i = 0; i < functions.size(); ++i)
994 functions[i]->body()->mark();
995
996 for (size_t i = 0; i < functionExpressions.size(); ++i)
997 functionExpressions[i]->body()->mark();
998}
999
1000bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth)
1001{
1002 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1003 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1004 unsigned addressOffset = vPC - instructions.begin();
1005 ASSERT(addressOffset < instructions.size());
1006
1007 for (; ptr != end; ++ptr) {
1008 // Handlers are ordered innermost first, so the first handler we encounter
1009 // that contains the source address is the correct handler to use.
1010 if (ptr->start <= addressOffset && ptr->end >= addressOffset) {
1011 scopeDepth = ptr->scopeDepth;
1012 target = instructions.begin() + ptr->target;
1013 return true;
1014 }
1015 }
1016 return false;
1017}
1018
1019void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
1020{
1021 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1022 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1023
1024 for (; ptr != end; ++ptr) {
1025 Instruction*target = instructions.begin() + ptr->target;
1026 if (handlerVPC == target)
1027 return ptr->nativeCode;
1028 }
1029
1030 return 0;
1031}
1032
1033int CodeBlock::lineNumberForVPC(const Instruction* vPC)
1034{
1035 ASSERT(lineInfo.size());
1036 unsigned instructionOffset = vPC - instructions.begin();
1037 ASSERT(instructionOffset < instructions.size());
1038
1039 if (!lineInfo.size())
1040 return 1; // Empty function
1041
1042 int low = 0;
1043 int high = lineInfo.size();
1044 while (low < high) {
1045 int mid = low + (high - low) / 2;
1046 if (lineInfo[mid].instructionOffset <= instructionOffset)
1047 low = mid + 1;
1048 else
1049 high = mid;
1050 }
1051 return lineInfo[low - 1].lineNumber;
1052}
1053
1054int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
1055{
1056 unsigned instructionOffset = vPC - instructions.begin();
1057 ASSERT(instructionOffset < instructions.size());
1058
1059 if (!expressionInfo.size()) {
1060 // We didn't think anything could throw. Apparently we were wrong.
1061 startOffset = 0;
1062 endOffset = 0;
1063 divot = 0;
1064 return lineNumberForVPC(vPC);
1065 }
1066
1067 int low = 0;
1068 int high = expressionInfo.size();
1069 while (low < high) {
1070 int mid = low + (high - low) / 2;
1071 if (expressionInfo[mid].instructionOffset <= instructionOffset)
1072 low = mid + 1;
1073 else
1074 high = mid;
1075 }
1076
1077 ASSERT(low);
1078 if (!low) {
1079 startOffset = 0;
1080 endOffset = 0;
1081 divot = 0;
1082 return lineNumberForVPC(vPC);
1083 }
1084
1085 startOffset = expressionInfo[low - 1].startOffset;
1086 endOffset = expressionInfo[low - 1].endOffset;
1087 divot = expressionInfo[low - 1].divotPoint + sourceOffset;
1088 return lineNumberForVPC(vPC);
1089}
1090
1091int32_t SimpleJumpTable::offsetForValue(int32_t value, int32_t defaultOffset)
1092{
1093 if (value >= min && static_cast<uint32_t>(value - min) < branchOffsets.size()) {
1094 int32_t offset = branchOffsets[value - min];
1095 if (offset)
1096 return offset;
1097 }
1098 return defaultOffset;
1099}
1100
1101} // namespace JSC
Note: See TracBrowser for help on using the repository browser.