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

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

Initial work to reduce cost of JSNumberCell allocation

Reviewed by Geoffrey Garen

This does the initial work needed to bring more of number
allocation into CTI code directly, rather than just falling
back onto the slow paths if we can't guarantee that a number
cell can be reused.

Initial implementation only used by op_negate to make sure
it all works. In a negate heavy (though not dominated) test
it results in a 10% win in the non-reusable cell case.

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