source: webkit/trunk/JavaScriptCore/bytecode/Opcode.h@ 52028

Last change on this file since 52028 was 51735, checked in by [email protected], 15 years ago

2009-12-05 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

<1% speedup on SunSpider and V8
2x speedup on "conway" benchmark


Two optimizations:

1) Improve codegen for logical operators &&,
and ! in a condition context


When generating code for combinations of &&,
and !, in a

condition context (i.e. in an if statement or loop condition), we
used to produce a value, and then separately jump based on its
truthiness. Now we pass the false and true targets in, and let the
logical operators generate jumps directly. This helps in four
ways:

a) Individual clauses of a short-circuit logical operator can now
jump directly to the then or else clause of an if statement (or to
the top or exit of a loop) instead of jumping to a jump.


b) It used to be that jump fusion with the condition of the first
clause of a logical operator was inhibited, because the register
was ref'd to be used later, in the actual condition jump; this no
longer happens since a jump straight to the final target is
generated directly.

c) It used to be that jump fusion with the condition of the second
clause of a logical operator was inhibited, because there was a
jump target right after the second clause and before the actual
condition jump. But now it's no longer necessary for the first
clause to jump there so jump fusion is not blocked.

d) We avoid generating excess mov statements in some cases.


As a concrete example this source:


if (!((x < q && y < q)
(t < q && z < q))) {

...

}


Used to generate this bytecode:


[ 34] less r1, r-15, r-19
[ 38] jfalse r1, 7(->45)
[ 41] less r1, r-16, r-19
[ 45] jtrue r1, 14(->59)
[ 48] less r1, r-17, r-19
[ 52] jfalse r1, 7(->59)
[ 55] less r1, r-18, r-19
[ 59] jtrue r1, 17(->76)


And now generates this bytecode (also taking advantage of the second optimization below):


[ 34] jnless r-15, r-19, 8(->42)
[ 38] jless r-16, r-19, 26(->64)
[ 42] jnless r-17, r-19, 8(->50)
[ 46] jless r-18, r-19, 18(->64)


Note the jump fusion and the fact that there's less jump
indirection - three of the four jumps go straight to the target
clause instead of indirecting through another jump.


2) Implement jless opcode to take advantage of the above, since we'll now often generate
a less followed by a jtrue where fusion is not forbidden.


  • parser/Nodes.h: (JSC::ExpressionNode::hasConditionContextCodegen): Helper function to determine whether a node supports special conditional codegen. Return false as this is the default. (JSC::ExpressionNode::emitBytecodeInConditionContext): Assert not reached - only really defined for nodes that do have conditional codegen. (JSC::UnaryOpNode::expr): Add const version. (JSC::LogicalNotNode::hasConditionContextCodegen): Returne true only if subexpression supports it. (JSC::LogicalOpNode::hasConditionContextCodegen): Return true.
  • parser/Nodes.cpp: (JSC::LogicalNotNode::emitBytecodeInConditionContext): Implemented - just swap the true and false targets for the child node. (JSC::LogicalOpNode::emitBytecodeInConditionContext): Implemented - handle jumps directly, improving codegen quality. Also handles further nested conditional codegen. (JSC::ConditionalNode::emitBytecode): Use condition context codegen when available. (JSC::IfNode::emitBytecode): ditto (JSC::IfElseNode::emitBytecode): ditto (JSC::DoWhileNode::emitBytecode): ditto (JSC::WhileNode::emitBytecode): ditto (JSC::ForNode::emitBytecode): ditto
  • bytecode/Opcode.h:
  • Added loop_if_false opcode - needed now that falsey jumps can be backwards.
  • Added jless opcode to take advantage of new fusion opportunities.
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): Handle above.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitJumpIfTrue): Add peephole for less + jtrue ==> jless. (JSC::BytecodeGenerator::emitJumpIfFalse): Add handling of backwrds falsey jumps.
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::emitNodeInConditionContext): Wrapper to handle tracking of overly deep expressions etc.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): Implement the two new opcodes (loop_if_false, jless).
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): Implement JIT support for the two new opcodes. (JSC::JIT::privateCompileSlowCases): ditto
  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::emit_op_jless): (JSC::JIT::emitSlow_op_jless): ditto (JSC::JIT::emitBinaryDoubleOp): ditto
  • jit/JITOpcodes.cpp: (JSC::JIT::emitSlow_op_loop_if_less): ditto (JSC::JIT::emit_op_loop_if_false): ditto (JSC::JIT::emitSlow_op_loop_if_false): ditto
  • jit/JITStubs.cpp:
  • jit/JITStubs.h: (JSC::):

2009-12-05 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

  • fast/js/codegen-loops-logical-nodes-expected.txt:
  • fast/js/script-tests/codegen-loops-logical-nodes.js: Update to test some newly sensitive cases of codegen that were not already covered.
File size: 7.7 KB
Line 
1/*
2 * Copyright (C) 2008, 2009 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#ifndef Opcode_h
31#define Opcode_h
32
33#include <algorithm>
34#include <string.h>
35
36#include <wtf/Assertions.h>
37
38namespace JSC {
39
40 #define FOR_EACH_OPCODE_ID(macro) \
41 macro(op_enter, 1) \
42 macro(op_enter_with_activation, 2) \
43 macro(op_init_arguments, 1) \
44 macro(op_create_arguments, 1) \
45 macro(op_convert_this, 2) \
46 \
47 macro(op_new_object, 2) \
48 macro(op_new_array, 4) \
49 macro(op_new_regexp, 3) \
50 macro(op_mov, 3) \
51 \
52 macro(op_not, 3) \
53 macro(op_eq, 4) \
54 macro(op_eq_null, 3) \
55 macro(op_neq, 4) \
56 macro(op_neq_null, 3) \
57 macro(op_stricteq, 4) \
58 macro(op_nstricteq, 4) \
59 macro(op_less, 4) \
60 macro(op_lesseq, 4) \
61 \
62 macro(op_pre_inc, 2) \
63 macro(op_pre_dec, 2) \
64 macro(op_post_inc, 3) \
65 macro(op_post_dec, 3) \
66 macro(op_to_jsnumber, 3) \
67 macro(op_negate, 3) \
68 macro(op_add, 5) \
69 macro(op_mul, 5) \
70 macro(op_div, 5) \
71 macro(op_mod, 4) \
72 macro(op_sub, 5) \
73 \
74 macro(op_lshift, 4) \
75 macro(op_rshift, 4) \
76 macro(op_urshift, 4) \
77 macro(op_bitand, 5) \
78 macro(op_bitxor, 5) \
79 macro(op_bitor, 5) \
80 macro(op_bitnot, 3) \
81 \
82 macro(op_instanceof, 5) \
83 macro(op_typeof, 3) \
84 macro(op_is_undefined, 3) \
85 macro(op_is_boolean, 3) \
86 macro(op_is_number, 3) \
87 macro(op_is_string, 3) \
88 macro(op_is_object, 3) \
89 macro(op_is_function, 3) \
90 macro(op_in, 4) \
91 \
92 macro(op_resolve, 3) \
93 macro(op_resolve_skip, 4) \
94 macro(op_resolve_global, 6) \
95 macro(op_get_scoped_var, 4) \
96 macro(op_put_scoped_var, 4) \
97 macro(op_get_global_var, 4) \
98 macro(op_put_global_var, 4) \
99 macro(op_resolve_base, 3) \
100 macro(op_resolve_with_base, 4) \
101 macro(op_get_by_id, 8) \
102 macro(op_get_by_id_self, 8) \
103 macro(op_get_by_id_self_list, 8) \
104 macro(op_get_by_id_proto, 8) \
105 macro(op_get_by_id_proto_list, 8) \
106 macro(op_get_by_id_chain, 8) \
107 macro(op_get_by_id_generic, 8) \
108 macro(op_get_array_length, 8) \
109 macro(op_get_string_length, 8) \
110 macro(op_put_by_id, 8) \
111 macro(op_put_by_id_transition, 8) \
112 macro(op_put_by_id_replace, 8) \
113 macro(op_put_by_id_generic, 8) \
114 macro(op_del_by_id, 4) \
115 macro(op_get_by_val, 4) \
116 macro(op_get_by_pname, 7) \
117 macro(op_put_by_val, 4) \
118 macro(op_del_by_val, 4) \
119 macro(op_put_by_index, 4) \
120 macro(op_put_getter, 4) \
121 macro(op_put_setter, 4) \
122 \
123 macro(op_jmp, 2) \
124 macro(op_jtrue, 3) \
125 macro(op_jfalse, 3) \
126 macro(op_jeq_null, 3) \
127 macro(op_jneq_null, 3) \
128 macro(op_jneq_ptr, 4) \
129 macro(op_jnless, 4) \
130 macro(op_jnlesseq, 4) \
131 macro(op_jless, 4) \
132 macro(op_jmp_scopes, 3) \
133 macro(op_loop, 2) \
134 macro(op_loop_if_true, 3) \
135 macro(op_loop_if_false, 3) \
136 macro(op_loop_if_less, 4) \
137 macro(op_loop_if_lesseq, 4) \
138 macro(op_switch_imm, 4) \
139 macro(op_switch_char, 4) \
140 macro(op_switch_string, 4) \
141 \
142 macro(op_new_func, 3) \
143 macro(op_new_func_exp, 3) \
144 macro(op_call, 5) \
145 macro(op_call_eval, 5) \
146 macro(op_call_varargs, 5) \
147 macro(op_load_varargs, 3) \
148 macro(op_tear_off_activation, 2) \
149 macro(op_tear_off_arguments, 1) \
150 macro(op_ret, 2) \
151 macro(op_method_check, 1) \
152 \
153 macro(op_construct, 7) \
154 macro(op_construct_verify, 3) \
155 macro(op_strcat, 4) \
156 macro(op_to_primitive, 3) \
157 \
158 macro(op_get_pnames, 6) \
159 macro(op_next_pname, 7) \
160 \
161 macro(op_push_scope, 2) \
162 macro(op_pop_scope, 1) \
163 macro(op_push_new_scope, 4) \
164 \
165 macro(op_catch, 2) \
166 macro(op_throw, 2) \
167 macro(op_new_error, 4) \
168 \
169 macro(op_jsr, 3) \
170 macro(op_sret, 2) \
171 \
172 macro(op_debug, 4) \
173 macro(op_profile_will_call, 2) \
174 macro(op_profile_did_call, 2) \
175 \
176 macro(op_end, 2) // end must be the last opcode in the list
177
178 #define OPCODE_ID_ENUM(opcode, length) opcode,
179 typedef enum { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) } OpcodeID;
180 #undef OPCODE_ID_ENUM
181
182 const int numOpcodeIDs = op_end + 1;
183
184 #define OPCODE_ID_LENGTHS(id, length) const int id##_length = length;
185 FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTHS);
186 #undef OPCODE_ID_LENGTHS
187
188 #define OPCODE_LENGTH(opcode) opcode##_length
189
190 #define OPCODE_ID_LENGTH_MAP(opcode, length) length,
191 const int opcodeLengths[numOpcodeIDs] = { FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTH_MAP) };
192 #undef OPCODE_ID_LENGTH_MAP
193
194 #define VERIFY_OPCODE_ID(id, size) COMPILE_ASSERT(id <= op_end, ASSERT_THAT_JS_OPCODE_IDS_ARE_VALID);
195 FOR_EACH_OPCODE_ID(VERIFY_OPCODE_ID);
196 #undef VERIFY_OPCODE_ID
197
198#if HAVE(COMPUTED_GOTO)
199 typedef void* Opcode;
200#else
201 typedef OpcodeID Opcode;
202#endif
203
204#if ENABLE(OPCODE_SAMPLING) || ENABLE(CODEBLOCK_SAMPLING) || ENABLE(OPCODE_STATS)
205
206#define PADDING_STRING " "
207#define PADDING_STRING_LENGTH static_cast<unsigned>(strlen(PADDING_STRING))
208
209 extern const char* const opcodeNames[];
210
211 inline const char* padOpcodeName(OpcodeID op, unsigned width)
212 {
213 unsigned pad = width - strlen(opcodeNames[op]);
214 pad = std::min(pad, PADDING_STRING_LENGTH);
215 return PADDING_STRING + PADDING_STRING_LENGTH - pad;
216 }
217
218#undef PADDING_STRING_LENGTH
219#undef PADDING_STRING
220
221#endif
222
223#if ENABLE(OPCODE_STATS)
224
225 struct OpcodeStats {
226 OpcodeStats();
227 ~OpcodeStats();
228 static long long opcodeCounts[numOpcodeIDs];
229 static long long opcodePairCounts[numOpcodeIDs][numOpcodeIDs];
230 static int lastOpcode;
231
232 static void recordInstruction(int opcode);
233 static void resetLastInstruction();
234 };
235
236#endif
237
238} // namespace JSC
239
240#endif // Opcode_h
Note: See TracBrowser for help on using the repository browser.