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

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

2008-10-06 Cameron Zwarich <[email protected]>

Reviewed by Oliver Hunt.

Bug 21396: Remove the OptionalCalleeActivation call frame slot
<https://bugs.webkit.org/show_bug.cgi?id=21396>

Remove the OptionalCalleeActivation call frame slot. We have to be
careful to store the activation object in a register, because objects
in the scope chain do not get marked.

This is a 0.3% speedup on both SunSpider and the V8 benchmark.

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