|
1 /* |
|
2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) |
|
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
|
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
|
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) |
|
6 * Copyright (C) 2007 Maks Orlovich |
|
7 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
|
8 * |
|
9 * This library is free software; you can redistribute it and/or |
|
10 * modify it under the terms of the GNU Library General Public |
|
11 * License as published by the Free Software Foundation; either |
|
12 * version 2 of the License, or (at your option) any later version. |
|
13 * |
|
14 * This library is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
17 * Library General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU Library General Public License |
|
20 * along with this library; see the file COPYING.LIB. If not, write to |
|
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
22 * Boston, MA 02110-1301, USA. |
|
23 * |
|
24 */ |
|
25 |
|
26 #include "config.h" |
|
27 #include "Nodes.h" |
|
28 #include "NodeConstructors.h" |
|
29 |
|
30 #include "BytecodeGenerator.h" |
|
31 #include "CallFrame.h" |
|
32 #include "Debugger.h" |
|
33 #include "JIT.h" |
|
34 #include "JSFunction.h" |
|
35 #include "JSGlobalObject.h" |
|
36 #include "JSStaticScopeObject.h" |
|
37 #include "LabelScope.h" |
|
38 #include "Lexer.h" |
|
39 #include "Operations.h" |
|
40 #include "Parser.h" |
|
41 #include "PropertyNameArray.h" |
|
42 #include "RegExpCache.h" |
|
43 #include "RegExpObject.h" |
|
44 #include "SamplingTool.h" |
|
45 #include <wtf/Assertions.h> |
|
46 #include <wtf/RefCountedLeakCounter.h> |
|
47 #include <wtf/Threading.h> |
|
48 |
|
49 using namespace WTF; |
|
50 |
|
51 namespace JSC { |
|
52 |
|
53 /* |
|
54 Details of the emitBytecode function. |
|
55 |
|
56 Return value: The register holding the production's value. |
|
57 dst: An optional parameter specifying the most efficient destination at |
|
58 which to store the production's value. The callee must honor dst. |
|
59 |
|
60 The dst argument provides for a crude form of copy propagation. For example, |
|
61 |
|
62 x = 1 |
|
63 |
|
64 becomes |
|
65 |
|
66 load r[x], 1 |
|
67 |
|
68 instead of |
|
69 |
|
70 load r0, 1 |
|
71 mov r[x], r0 |
|
72 |
|
73 because the assignment node, "x =", passes r[x] as dst to the number node, "1". |
|
74 */ |
|
75 |
|
76 // ------------------------------ ThrowableExpressionData -------------------------------- |
|
77 |
|
78 static void substitute(UString& string, const UString& substring) |
|
79 { |
|
80 unsigned position = string.find("%s"); |
|
81 ASSERT(position != UString::NotFound); |
|
82 string = makeString(string.substr(0, position), substring, string.substr(position + 2)); |
|
83 } |
|
84 |
|
85 RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* message) |
|
86 { |
|
87 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
88 RegisterID* exception = generator.emitNewError(generator.newTemporary(), isReferenceError, jsString(generator.globalData(), message)); |
|
89 generator.emitThrow(exception); |
|
90 return exception; |
|
91 } |
|
92 |
|
93 RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* messageTemplate, const UString& label) |
|
94 { |
|
95 UString message = messageTemplate; |
|
96 substitute(message, label); |
|
97 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
98 RegisterID* exception = generator.emitNewError(generator.newTemporary(), isReferenceError, jsString(generator.globalData(), message)); |
|
99 generator.emitThrow(exception); |
|
100 return exception; |
|
101 } |
|
102 |
|
103 inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* messageTemplate, const Identifier& label) |
|
104 { |
|
105 return emitThrowError(generator, isReferenceError, messageTemplate, label.ustring()); |
|
106 } |
|
107 |
|
108 // ------------------------------ NullNode ------------------------------------- |
|
109 |
|
110 RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
111 { |
|
112 if (dst == generator.ignoredResult()) |
|
113 return 0; |
|
114 return generator.emitLoad(dst, jsNull()); |
|
115 } |
|
116 |
|
117 // ------------------------------ BooleanNode ---------------------------------- |
|
118 |
|
119 RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
120 { |
|
121 if (dst == generator.ignoredResult()) |
|
122 return 0; |
|
123 return generator.emitLoad(dst, m_value); |
|
124 } |
|
125 |
|
126 // ------------------------------ NumberNode ----------------------------------- |
|
127 |
|
128 RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
129 { |
|
130 if (dst == generator.ignoredResult()) |
|
131 return 0; |
|
132 return generator.emitLoad(dst, m_value); |
|
133 } |
|
134 |
|
135 // ------------------------------ StringNode ----------------------------------- |
|
136 |
|
137 RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
138 { |
|
139 if (dst == generator.ignoredResult()) |
|
140 return 0; |
|
141 return generator.emitLoad(dst, m_value); |
|
142 } |
|
143 |
|
144 // ------------------------------ RegExpNode ----------------------------------- |
|
145 |
|
146 RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
147 { |
|
148 RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring()); |
|
149 if (!regExp->isValid()) |
|
150 return emitThrowError(generator, false, "Invalid regular expression: %s", regExp->errorMessage()); |
|
151 if (dst == generator.ignoredResult()) |
|
152 return 0; |
|
153 return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); |
|
154 } |
|
155 |
|
156 // ------------------------------ ThisNode ------------------------------------- |
|
157 |
|
158 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
159 { |
|
160 if (dst == generator.ignoredResult()) |
|
161 return 0; |
|
162 return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); |
|
163 } |
|
164 |
|
165 // ------------------------------ ResolveNode ---------------------------------- |
|
166 |
|
167 bool ResolveNode::isPure(BytecodeGenerator& generator) const |
|
168 { |
|
169 return generator.isLocal(m_ident); |
|
170 } |
|
171 |
|
172 RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
173 { |
|
174 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
175 if (dst == generator.ignoredResult()) |
|
176 return 0; |
|
177 return generator.moveToDestinationIfNeeded(dst, local); |
|
178 } |
|
179 |
|
180 generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); |
|
181 return generator.emitResolve(generator.finalDestination(dst), m_ident); |
|
182 } |
|
183 |
|
184 // ------------------------------ ArrayNode ------------------------------------ |
|
185 |
|
186 RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
187 { |
|
188 // FIXME: Should we put all of this code into emitNewArray? |
|
189 |
|
190 unsigned length = 0; |
|
191 ElementNode* firstPutElement; |
|
192 for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { |
|
193 if (firstPutElement->elision()) |
|
194 break; |
|
195 ++length; |
|
196 } |
|
197 |
|
198 if (!firstPutElement && !m_elision) |
|
199 return generator.emitNewArray(generator.finalDestination(dst), m_element); |
|
200 |
|
201 RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element); |
|
202 |
|
203 for (ElementNode* n = firstPutElement; n; n = n->next()) { |
|
204 RegisterID* value = generator.emitNode(n->value()); |
|
205 length += n->elision(); |
|
206 generator.emitPutByIndex(array.get(), length++, value); |
|
207 } |
|
208 |
|
209 if (m_elision) { |
|
210 RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); |
|
211 generator.emitPutById(array.get(), generator.propertyNames().length, value); |
|
212 } |
|
213 |
|
214 return generator.moveToDestinationIfNeeded(dst, array.get()); |
|
215 } |
|
216 |
|
217 bool ArrayNode::isSimpleArray() const |
|
218 { |
|
219 if (m_elision || m_optional) |
|
220 return false; |
|
221 for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { |
|
222 if (ptr->elision()) |
|
223 return false; |
|
224 } |
|
225 return true; |
|
226 } |
|
227 |
|
228 ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const |
|
229 { |
|
230 ASSERT(!m_elision && !m_optional); |
|
231 ElementNode* ptr = m_element; |
|
232 if (!ptr) |
|
233 return 0; |
|
234 ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); |
|
235 ArgumentListNode* tail = head; |
|
236 ptr = ptr->next(); |
|
237 for (; ptr; ptr = ptr->next()) { |
|
238 ASSERT(!ptr->elision()); |
|
239 tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); |
|
240 } |
|
241 return head; |
|
242 } |
|
243 |
|
244 // ------------------------------ ObjectLiteralNode ---------------------------- |
|
245 |
|
246 RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
247 { |
|
248 if (!m_list) { |
|
249 if (dst == generator.ignoredResult()) |
|
250 return 0; |
|
251 return generator.emitNewObject(generator.finalDestination(dst)); |
|
252 } |
|
253 return generator.emitNode(dst, m_list); |
|
254 } |
|
255 |
|
256 // ------------------------------ PropertyListNode ----------------------------- |
|
257 |
|
258 RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
259 { |
|
260 RefPtr<RegisterID> newObj = generator.tempDestination(dst); |
|
261 |
|
262 generator.emitNewObject(newObj.get()); |
|
263 |
|
264 for (PropertyListNode* p = this; p; p = p->m_next) { |
|
265 RegisterID* value = generator.emitNode(p->m_node->m_assign); |
|
266 |
|
267 switch (p->m_node->m_type) { |
|
268 case PropertyNode::Constant: { |
|
269 generator.emitDirectPutById(newObj.get(), p->m_node->name(), value); |
|
270 break; |
|
271 } |
|
272 case PropertyNode::Getter: { |
|
273 generator.emitPutGetter(newObj.get(), p->m_node->name(), value); |
|
274 break; |
|
275 } |
|
276 case PropertyNode::Setter: { |
|
277 generator.emitPutSetter(newObj.get(), p->m_node->name(), value); |
|
278 break; |
|
279 } |
|
280 default: |
|
281 ASSERT_NOT_REACHED(); |
|
282 } |
|
283 } |
|
284 |
|
285 return generator.moveToDestinationIfNeeded(dst, newObj.get()); |
|
286 } |
|
287 |
|
288 // ------------------------------ BracketAccessorNode -------------------------------- |
|
289 |
|
290 RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
291 { |
|
292 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); |
|
293 RegisterID* property = generator.emitNode(m_subscript); |
|
294 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
295 return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); |
|
296 } |
|
297 |
|
298 // ------------------------------ DotAccessorNode -------------------------------- |
|
299 |
|
300 RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
301 { |
|
302 RegisterID* base = generator.emitNode(m_base); |
|
303 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
304 return generator.emitGetById(generator.finalDestination(dst), base, m_ident); |
|
305 } |
|
306 |
|
307 // ------------------------------ ArgumentListNode ----------------------------- |
|
308 |
|
309 RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
310 { |
|
311 ASSERT(m_expr); |
|
312 return generator.emitNode(dst, m_expr); |
|
313 } |
|
314 |
|
315 // ------------------------------ NewExprNode ---------------------------------- |
|
316 |
|
317 RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
318 { |
|
319 RefPtr<RegisterID> func = generator.emitNode(m_expr); |
|
320 CallArguments callArguments(generator, m_args); |
|
321 return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset()); |
|
322 } |
|
323 |
|
324 CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) |
|
325 : m_argumentsNode(argumentsNode) |
|
326 { |
|
327 if (generator.shouldEmitProfileHooks()) |
|
328 m_profileHookRegister = generator.newTemporary(); |
|
329 m_argv.append(generator.newTemporary()); |
|
330 if (argumentsNode) { |
|
331 for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) { |
|
332 m_argv.append(generator.newTemporary()); |
|
333 // op_call requires the arguments to be a sequential range of registers |
|
334 ASSERT(m_argv[m_argv.size() - 1]->index() == m_argv[m_argv.size() - 2]->index() + 1); |
|
335 } |
|
336 } |
|
337 } |
|
338 |
|
339 // ------------------------------ EvalFunctionCallNode ---------------------------------- |
|
340 |
|
341 RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
342 { |
|
343 RefPtr<RegisterID> func = generator.tempDestination(dst); |
|
344 CallArguments callArguments(generator, m_args); |
|
345 generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); |
|
346 generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); |
|
347 return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); |
|
348 } |
|
349 |
|
350 // ------------------------------ FunctionCallValueNode ---------------------------------- |
|
351 |
|
352 RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
353 { |
|
354 RefPtr<RegisterID> func = generator.emitNode(m_expr); |
|
355 CallArguments callArguments(generator, m_args); |
|
356 generator.emitLoad(callArguments.thisRegister(), jsNull()); |
|
357 return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); |
|
358 } |
|
359 |
|
360 // ------------------------------ FunctionCallResolveNode ---------------------------------- |
|
361 |
|
362 RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
363 { |
|
364 if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { |
|
365 CallArguments callArguments(generator, m_args); |
|
366 generator.emitLoad(callArguments.thisRegister(), jsNull()); |
|
367 return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset()); |
|
368 } |
|
369 |
|
370 int index = 0; |
|
371 size_t depth = 0; |
|
372 JSObject* globalObject = 0; |
|
373 bool requiresDynamicChecks = false; |
|
374 if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { |
|
375 RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); |
|
376 CallArguments callArguments(generator, m_args); |
|
377 generator.emitLoad(callArguments.thisRegister(), jsNull()); |
|
378 return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); |
|
379 } |
|
380 |
|
381 RefPtr<RegisterID> func = generator.newTemporary(); |
|
382 CallArguments callArguments(generator, m_args); |
|
383 int identifierStart = divot() - startOffset(); |
|
384 generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); |
|
385 generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), m_ident); |
|
386 return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); |
|
387 } |
|
388 |
|
389 // ------------------------------ FunctionCallBracketNode ---------------------------------- |
|
390 |
|
391 RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
392 { |
|
393 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
394 RegisterID* property = generator.emitNode(m_subscript); |
|
395 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
396 RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); |
|
397 CallArguments callArguments(generator, m_args); |
|
398 generator.emitMove(callArguments.thisRegister(), base.get()); |
|
399 return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); |
|
400 } |
|
401 |
|
402 // ------------------------------ FunctionCallDotNode ---------------------------------- |
|
403 |
|
404 RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
405 { |
|
406 RefPtr<RegisterID> function = generator.tempDestination(dst); |
|
407 CallArguments callArguments(generator, m_args); |
|
408 generator.emitNode(callArguments.thisRegister(), m_base); |
|
409 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
410 generator.emitMethodCheck(); |
|
411 generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); |
|
412 return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); |
|
413 } |
|
414 |
|
415 RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
416 { |
|
417 RefPtr<Label> realCall = generator.newLabel(); |
|
418 RefPtr<Label> end = generator.newLabel(); |
|
419 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
420 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
421 RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
|
422 RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); |
|
423 generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); |
|
424 { |
|
425 if (m_args->m_listNode && m_args->m_listNode->m_expr) { |
|
426 ArgumentListNode* oldList = m_args->m_listNode; |
|
427 m_args->m_listNode = m_args->m_listNode->m_next; |
|
428 |
|
429 RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
|
430 CallArguments callArguments(generator, m_args); |
|
431 generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
|
432 generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); |
|
433 generator.emitJump(end.get()); |
|
434 |
|
435 m_args->m_listNode = oldList; |
|
436 |
|
437 } else { |
|
438 RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
|
439 CallArguments callArguments(generator, m_args); |
|
440 generator.emitLoad(callArguments.thisRegister(), jsNull()); |
|
441 generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); |
|
442 generator.emitJump(end.get()); |
|
443 } |
|
444 } |
|
445 generator.emitLabel(realCall.get()); |
|
446 { |
|
447 CallArguments callArguments(generator, m_args); |
|
448 generator.emitMove(callArguments.thisRegister(), base.get()); |
|
449 generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); |
|
450 } |
|
451 generator.emitLabel(end.get()); |
|
452 return finalDestinationOrIgnored.get(); |
|
453 } |
|
454 |
|
455 static bool areTrivialApplyArguments(ArgumentsNode* args) |
|
456 { |
|
457 return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next |
|
458 || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); |
|
459 } |
|
460 |
|
461 RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
462 { |
|
463 // A few simple cases can be trivially handled as ordinary function calls. |
|
464 // function.apply(), function.apply(arg) -> identical to function.call |
|
465 // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation |
|
466 bool mayBeCall = areTrivialApplyArguments(m_args); |
|
467 |
|
468 RefPtr<Label> realCall = generator.newLabel(); |
|
469 RefPtr<Label> end = generator.newLabel(); |
|
470 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
471 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
472 RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
|
473 RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); |
|
474 generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); |
|
475 { |
|
476 if (mayBeCall) { |
|
477 if (m_args->m_listNode && m_args->m_listNode->m_expr) { |
|
478 ArgumentListNode* oldList = m_args->m_listNode; |
|
479 if (m_args->m_listNode->m_next) { |
|
480 ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); |
|
481 ASSERT(!m_args->m_listNode->m_next->m_next); |
|
482 m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.globalData()); |
|
483 RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
|
484 CallArguments callArguments(generator, m_args); |
|
485 generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
|
486 generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); |
|
487 } else { |
|
488 m_args->m_listNode = m_args->m_listNode->m_next; |
|
489 RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
|
490 CallArguments callArguments(generator, m_args); |
|
491 generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
|
492 generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); |
|
493 } |
|
494 m_args->m_listNode = oldList; |
|
495 } else { |
|
496 RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
|
497 CallArguments callArguments(generator, m_args); |
|
498 generator.emitLoad(callArguments.thisRegister(), jsNull()); |
|
499 generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); |
|
500 } |
|
501 } else { |
|
502 ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); |
|
503 RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); |
|
504 RefPtr<RegisterID> argsCountRegister = generator.newTemporary(); |
|
505 RefPtr<RegisterID> thisRegister = generator.newTemporary(); |
|
506 RefPtr<RegisterID> argsRegister = generator.newTemporary(); |
|
507 generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); |
|
508 ArgumentListNode* args = m_args->m_listNode->m_next; |
|
509 bool isArgumentsApply = false; |
|
510 if (args->m_expr->isResolveNode()) { |
|
511 ResolveNode* resolveNode = static_cast<ResolveNode*>(args->m_expr); |
|
512 isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); |
|
513 if (isArgumentsApply) |
|
514 generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); |
|
515 } |
|
516 if (!isArgumentsApply) |
|
517 generator.emitNode(argsRegister.get(), args->m_expr); |
|
518 while ((args = args->m_next)) |
|
519 generator.emitNode(args->m_expr); |
|
520 |
|
521 generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); |
|
522 generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); |
|
523 } |
|
524 generator.emitJump(end.get()); |
|
525 } |
|
526 generator.emitLabel(realCall.get()); |
|
527 { |
|
528 CallArguments callArguments(generator, m_args); |
|
529 generator.emitMove(callArguments.thisRegister(), base.get()); |
|
530 generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); |
|
531 } |
|
532 generator.emitLabel(end.get()); |
|
533 return finalDestinationOrIgnored.get(); |
|
534 } |
|
535 |
|
536 // ------------------------------ PostfixResolveNode ---------------------------------- |
|
537 |
|
538 static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) |
|
539 { |
|
540 return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); |
|
541 } |
|
542 |
|
543 static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) |
|
544 { |
|
545 if (srcDst == dst) |
|
546 return generator.emitToJSNumber(dst, srcDst); |
|
547 return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); |
|
548 } |
|
549 |
|
550 RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
551 { |
|
552 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
553 if (generator.isLocalConstant(m_ident)) { |
|
554 if (dst == generator.ignoredResult()) |
|
555 return 0; |
|
556 return generator.emitToJSNumber(generator.finalDestination(dst), local); |
|
557 } |
|
558 |
|
559 if (dst == generator.ignoredResult()) |
|
560 return emitPreIncOrDec(generator, local, m_operator); |
|
561 return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); |
|
562 } |
|
563 |
|
564 int index = 0; |
|
565 size_t depth = 0; |
|
566 JSObject* globalObject = 0; |
|
567 bool requiresDynamicChecks = false; |
|
568 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { |
|
569 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); |
|
570 RegisterID* oldValue; |
|
571 if (dst == generator.ignoredResult()) { |
|
572 oldValue = 0; |
|
573 emitPreIncOrDec(generator, value.get(), m_operator); |
|
574 } else { |
|
575 oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); |
|
576 } |
|
577 generator.emitPutScopedVar(depth, index, value.get(), globalObject); |
|
578 return oldValue; |
|
579 } |
|
580 |
|
581 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
582 RefPtr<RegisterID> value = generator.newTemporary(); |
|
583 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); |
|
584 RegisterID* oldValue; |
|
585 if (dst == generator.ignoredResult()) { |
|
586 oldValue = 0; |
|
587 emitPreIncOrDec(generator, value.get(), m_operator); |
|
588 } else { |
|
589 oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); |
|
590 } |
|
591 generator.emitPutById(base.get(), m_ident, value.get()); |
|
592 return oldValue; |
|
593 } |
|
594 |
|
595 // ------------------------------ PostfixBracketNode ---------------------------------- |
|
596 |
|
597 RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
598 { |
|
599 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
600 RefPtr<RegisterID> property = generator.emitNode(m_subscript); |
|
601 |
|
602 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
603 RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); |
|
604 RegisterID* oldValue; |
|
605 if (dst == generator.ignoredResult()) { |
|
606 oldValue = 0; |
|
607 if (m_operator == OpPlusPlus) |
|
608 generator.emitPreInc(value.get()); |
|
609 else |
|
610 generator.emitPreDec(value.get()); |
|
611 } else { |
|
612 oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); |
|
613 } |
|
614 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
615 generator.emitPutByVal(base.get(), property.get(), value.get()); |
|
616 return oldValue; |
|
617 } |
|
618 |
|
619 // ------------------------------ PostfixDotNode ---------------------------------- |
|
620 |
|
621 RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
622 { |
|
623 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
624 |
|
625 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
626 RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); |
|
627 RegisterID* oldValue; |
|
628 if (dst == generator.ignoredResult()) { |
|
629 oldValue = 0; |
|
630 if (m_operator == OpPlusPlus) |
|
631 generator.emitPreInc(value.get()); |
|
632 else |
|
633 generator.emitPreDec(value.get()); |
|
634 } else { |
|
635 oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); |
|
636 } |
|
637 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
638 generator.emitPutById(base.get(), m_ident, value.get()); |
|
639 return oldValue; |
|
640 } |
|
641 |
|
642 // ------------------------------ PostfixErrorNode ----------------------------------- |
|
643 |
|
644 RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
645 { |
|
646 return emitThrowError(generator, true, m_operator == OpPlusPlus |
|
647 ? "Postfix ++ operator applied to value that is not a reference." |
|
648 : "Postfix -- operator applied to value that is not a reference."); |
|
649 } |
|
650 |
|
651 // ------------------------------ DeleteResolveNode ----------------------------------- |
|
652 |
|
653 RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
654 { |
|
655 if (generator.registerFor(m_ident)) |
|
656 return generator.emitLoad(generator.finalDestination(dst), false); |
|
657 |
|
658 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
659 RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); |
|
660 return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); |
|
661 } |
|
662 |
|
663 // ------------------------------ DeleteBracketNode ----------------------------------- |
|
664 |
|
665 RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
666 { |
|
667 RefPtr<RegisterID> r0 = generator.emitNode(m_base); |
|
668 RegisterID* r1 = generator.emitNode(m_subscript); |
|
669 |
|
670 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
671 return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); |
|
672 } |
|
673 |
|
674 // ------------------------------ DeleteDotNode ----------------------------------- |
|
675 |
|
676 RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
677 { |
|
678 RegisterID* r0 = generator.emitNode(m_base); |
|
679 |
|
680 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
681 return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); |
|
682 } |
|
683 |
|
684 // ------------------------------ DeleteValueNode ----------------------------------- |
|
685 |
|
686 RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
687 { |
|
688 generator.emitNode(generator.ignoredResult(), m_expr); |
|
689 |
|
690 // delete on a non-location expression ignores the value and returns true |
|
691 return generator.emitLoad(generator.finalDestination(dst), true); |
|
692 } |
|
693 |
|
694 // ------------------------------ VoidNode ------------------------------------- |
|
695 |
|
696 RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
697 { |
|
698 if (dst == generator.ignoredResult()) { |
|
699 generator.emitNode(generator.ignoredResult(), m_expr); |
|
700 return 0; |
|
701 } |
|
702 RefPtr<RegisterID> r0 = generator.emitNode(m_expr); |
|
703 return generator.emitLoad(dst, jsUndefined()); |
|
704 } |
|
705 |
|
706 // ------------------------------ TypeOfValueNode ----------------------------------- |
|
707 |
|
708 RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
709 { |
|
710 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
711 if (dst == generator.ignoredResult()) |
|
712 return 0; |
|
713 return generator.emitTypeOf(generator.finalDestination(dst), local); |
|
714 } |
|
715 |
|
716 RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); |
|
717 generator.emitGetById(scratch.get(), scratch.get(), m_ident); |
|
718 if (dst == generator.ignoredResult()) |
|
719 return 0; |
|
720 return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); |
|
721 } |
|
722 |
|
723 // ------------------------------ TypeOfValueNode ----------------------------------- |
|
724 |
|
725 RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
726 { |
|
727 if (dst == generator.ignoredResult()) { |
|
728 generator.emitNode(generator.ignoredResult(), m_expr); |
|
729 return 0; |
|
730 } |
|
731 RefPtr<RegisterID> src = generator.emitNode(m_expr); |
|
732 return generator.emitTypeOf(generator.finalDestination(dst), src.get()); |
|
733 } |
|
734 |
|
735 // ------------------------------ PrefixResolveNode ---------------------------------- |
|
736 |
|
737 RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
738 { |
|
739 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
740 if (generator.isLocalConstant(m_ident)) { |
|
741 if (dst == generator.ignoredResult()) |
|
742 return 0; |
|
743 RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); |
|
744 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); |
|
745 } |
|
746 |
|
747 emitPreIncOrDec(generator, local, m_operator); |
|
748 return generator.moveToDestinationIfNeeded(dst, local); |
|
749 } |
|
750 |
|
751 int index = 0; |
|
752 size_t depth = 0; |
|
753 JSObject* globalObject = 0; |
|
754 bool requiresDynamicChecks = false; |
|
755 if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { |
|
756 RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); |
|
757 emitPreIncOrDec(generator, propDst.get(), m_operator); |
|
758 generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); |
|
759 return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
|
760 } |
|
761 |
|
762 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
763 RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
|
764 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); |
|
765 emitPreIncOrDec(generator, propDst.get(), m_operator); |
|
766 generator.emitPutById(base.get(), m_ident, propDst.get()); |
|
767 return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
|
768 } |
|
769 |
|
770 // ------------------------------ PrefixBracketNode ---------------------------------- |
|
771 |
|
772 RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
773 { |
|
774 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
775 RefPtr<RegisterID> property = generator.emitNode(m_subscript); |
|
776 RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
|
777 |
|
778 generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); |
|
779 RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); |
|
780 if (m_operator == OpPlusPlus) |
|
781 generator.emitPreInc(value); |
|
782 else |
|
783 generator.emitPreDec(value); |
|
784 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
785 generator.emitPutByVal(base.get(), property.get(), value); |
|
786 return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
|
787 } |
|
788 |
|
789 // ------------------------------ PrefixDotNode ---------------------------------- |
|
790 |
|
791 RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
792 { |
|
793 RefPtr<RegisterID> base = generator.emitNode(m_base); |
|
794 RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
|
795 |
|
796 generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); |
|
797 RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident); |
|
798 if (m_operator == OpPlusPlus) |
|
799 generator.emitPreInc(value); |
|
800 else |
|
801 generator.emitPreDec(value); |
|
802 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
803 generator.emitPutById(base.get(), m_ident, value); |
|
804 return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
|
805 } |
|
806 |
|
807 // ------------------------------ PrefixErrorNode ----------------------------------- |
|
808 |
|
809 RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
810 { |
|
811 return emitThrowError(generator, true, m_operator == OpPlusPlus |
|
812 ? "Prefix ++ operator applied to value that is not a reference." |
|
813 : "Prefix -- operator applied to value that is not a reference."); |
|
814 } |
|
815 |
|
816 // ------------------------------ Unary Operation Nodes ----------------------------------- |
|
817 |
|
818 RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
819 { |
|
820 RegisterID* src = generator.emitNode(m_expr); |
|
821 return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); |
|
822 } |
|
823 |
|
824 |
|
825 // ------------------------------ LogicalNotNode ----------------------------------- |
|
826 |
|
827 void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) |
|
828 { |
|
829 ASSERT(expr()->hasConditionContextCodegen()); |
|
830 |
|
831 // reverse the true and false targets |
|
832 generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, !fallThroughMeansTrue); |
|
833 } |
|
834 |
|
835 |
|
836 // ------------------------------ Binary Operation Nodes ----------------------------------- |
|
837 |
|
838 // BinaryOpNode::emitStrcat: |
|
839 // |
|
840 // This node generates an op_strcat operation. This opcode can handle concatenation of three or |
|
841 // more values, where we can determine a set of separate op_add operations would be operating on |
|
842 // string values. |
|
843 // |
|
844 // This function expects to be operating on a graph of AST nodes looking something like this: |
|
845 // |
|
846 // (a)... (b) |
|
847 // \ / |
|
848 // (+) (c) |
|
849 // \ / |
|
850 // [d] ((+)) |
|
851 // \ / |
|
852 // [+=] |
|
853 // |
|
854 // The assignment operation is optional, if it exists the register holding the value on the |
|
855 // lefthand side of the assignment should be passing as the optional 'lhs' argument. |
|
856 // |
|
857 // The method should be called on the node at the root of the tree of regular binary add |
|
858 // operations (marked in the diagram with a double set of parentheses). This node must |
|
859 // be performing a string concatenation (determined by statically detecting that at least |
|
860 // one child must be a string). |
|
861 // |
|
862 // Since the minimum number of values being concatenated together is expected to be 3, if |
|
863 // a lhs to a concatenating assignment is not provided then the root add should have at |
|
864 // least one left child that is also an add that can be determined to be operating on strings. |
|
865 // |
|
866 RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) |
|
867 { |
|
868 ASSERT(isAdd()); |
|
869 ASSERT(resultDescriptor().definitelyIsString()); |
|
870 |
|
871 // Create a list of expressions for all the adds in the tree of nodes we can convert into |
|
872 // a string concatenation. The rightmost node (c) is added first. The rightmost node is |
|
873 // added first, and the leftmost child is never added, so the vector produced for the |
|
874 // example above will be [ c, b ]. |
|
875 Vector<ExpressionNode*, 16> reverseExpressionList; |
|
876 reverseExpressionList.append(m_expr2); |
|
877 |
|
878 // Examine the left child of the add. So long as this is a string add, add its right-child |
|
879 // to the list, and keep processing along the left fork. |
|
880 ExpressionNode* leftMostAddChild = m_expr1; |
|
881 while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { |
|
882 reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); |
|
883 leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; |
|
884 } |
|
885 |
|
886 Vector<RefPtr<RegisterID>, 16> temporaryRegisters; |
|
887 |
|
888 // If there is an assignment, allocate a temporary to hold the lhs after conversion. |
|
889 // We could possibly avoid this (the lhs is converted last anyway, we could let the |
|
890 // op_strcat node handle its conversion if required). |
|
891 if (lhs) |
|
892 temporaryRegisters.append(generator.newTemporary()); |
|
893 |
|
894 // Emit code for the leftmost node ((a) in the example). |
|
895 temporaryRegisters.append(generator.newTemporary()); |
|
896 RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); |
|
897 generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); |
|
898 |
|
899 // Note on ordering of conversions: |
|
900 // |
|
901 // We maintain the same ordering of conversions as we would see if the concatenations |
|
902 // was performed as a sequence of adds (otherwise this optimization could change |
|
903 // behaviour should an object have been provided a valueOf or toString method). |
|
904 // |
|
905 // Considering the above example, the sequnce of execution is: |
|
906 // * evaluate operand (a) |
|
907 // * evaluate operand (b) |
|
908 // * convert (a) to primitive <- (this would be triggered by the first add) |
|
909 // * convert (b) to primitive <- (ditto) |
|
910 // * evaluate operand (c) |
|
911 // * convert (c) to primitive <- (this would be triggered by the second add) |
|
912 // And optionally, if there is an assignment: |
|
913 // * convert (d) to primitive <- (this would be triggered by the assigning addition) |
|
914 // |
|
915 // As such we do not plant an op to convert the leftmost child now. Instead, use |
|
916 // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion |
|
917 // once the second node has been generated. However, if the leftmost child is an |
|
918 // immediate we can trivially determine that no conversion will be required. |
|
919 // If this is the case |
|
920 if (leftMostAddChild->isString()) |
|
921 leftMostAddChildTempRegister = 0; |
|
922 |
|
923 while (reverseExpressionList.size()) { |
|
924 ExpressionNode* node = reverseExpressionList.last(); |
|
925 reverseExpressionList.removeLast(); |
|
926 |
|
927 // Emit the code for the current node. |
|
928 temporaryRegisters.append(generator.newTemporary()); |
|
929 generator.emitNode(temporaryRegisters.last().get(), node); |
|
930 |
|
931 // On the first iteration of this loop, when we first reach this point we have just |
|
932 // generated the second node, which means it is time to convert the leftmost operand. |
|
933 if (leftMostAddChildTempRegister) { |
|
934 generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); |
|
935 leftMostAddChildTempRegister = 0; // Only do this once. |
|
936 } |
|
937 // Plant a conversion for this node, if necessary. |
|
938 if (!node->isString()) |
|
939 generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); |
|
940 } |
|
941 ASSERT(temporaryRegisters.size() >= 3); |
|
942 |
|
943 // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. |
|
944 // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. |
|
945 if (emitExpressionInfoForMe) |
|
946 generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); |
|
947 |
|
948 // If there is an assignment convert the lhs now. This will also copy lhs to |
|
949 // the temporary register we allocated for it. |
|
950 if (lhs) |
|
951 generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); |
|
952 |
|
953 return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); |
|
954 } |
|
955 |
|
956 RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
957 { |
|
958 OpcodeID opcodeID = this->opcodeID(); |
|
959 |
|
960 if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) |
|
961 return emitStrcat(generator, dst); |
|
962 |
|
963 if (opcodeID == op_neq) { |
|
964 if (m_expr1->isNull() || m_expr2->isNull()) { |
|
965 RefPtr<RegisterID> src = generator.tempDestination(dst); |
|
966 generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); |
|
967 return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); |
|
968 } |
|
969 } |
|
970 |
|
971 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
972 RegisterID* src2 = generator.emitNode(m_expr2); |
|
973 return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); |
|
974 } |
|
975 |
|
976 RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
977 { |
|
978 if (m_expr1->isNull() || m_expr2->isNull()) { |
|
979 RefPtr<RegisterID> src = generator.tempDestination(dst); |
|
980 generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); |
|
981 return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); |
|
982 } |
|
983 |
|
984 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
985 RegisterID* src2 = generator.emitNode(m_expr2); |
|
986 return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); |
|
987 } |
|
988 |
|
989 RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
990 { |
|
991 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
992 RegisterID* src2 = generator.emitNode(m_expr2); |
|
993 return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); |
|
994 } |
|
995 |
|
996 RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
997 { |
|
998 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
999 RegisterID* src2 = generator.emitNode(m_expr2); |
|
1000 return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); |
|
1001 } |
|
1002 |
|
1003 RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1004 { |
|
1005 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
1006 RegisterID* src2 = generator.emitNode(m_expr2); |
|
1007 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1008 return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); |
|
1009 } |
|
1010 |
|
1011 RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1012 { |
|
1013 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
|
1014 RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); |
|
1015 |
|
1016 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1017 generator.emitGetByIdExceptionInfo(op_instanceof); |
|
1018 RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); |
|
1019 |
|
1020 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1021 return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); |
|
1022 } |
|
1023 |
|
1024 // ------------------------------ LogicalOpNode ---------------------------- |
|
1025 |
|
1026 RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1027 { |
|
1028 RefPtr<RegisterID> temp = generator.tempDestination(dst); |
|
1029 RefPtr<Label> target = generator.newLabel(); |
|
1030 |
|
1031 generator.emitNode(temp.get(), m_expr1); |
|
1032 if (m_operator == OpLogicalAnd) |
|
1033 generator.emitJumpIfFalse(temp.get(), target.get()); |
|
1034 else |
|
1035 generator.emitJumpIfTrue(temp.get(), target.get()); |
|
1036 generator.emitNode(temp.get(), m_expr2); |
|
1037 generator.emitLabel(target.get()); |
|
1038 |
|
1039 return generator.moveToDestinationIfNeeded(dst, temp.get()); |
|
1040 } |
|
1041 |
|
1042 void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) |
|
1043 { |
|
1044 if (m_expr1->hasConditionContextCodegen()) { |
|
1045 RefPtr<Label> afterExpr1 = generator.newLabel(); |
|
1046 if (m_operator == OpLogicalAnd) |
|
1047 generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, true); |
|
1048 else |
|
1049 generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), false); |
|
1050 generator.emitLabel(afterExpr1.get()); |
|
1051 } else { |
|
1052 RegisterID* temp = generator.emitNode(m_expr1); |
|
1053 if (m_operator == OpLogicalAnd) |
|
1054 generator.emitJumpIfFalse(temp, falseTarget); |
|
1055 else |
|
1056 generator.emitJumpIfTrue(temp, trueTarget); |
|
1057 } |
|
1058 |
|
1059 if (m_expr2->hasConditionContextCodegen()) |
|
1060 generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMeansTrue); |
|
1061 else { |
|
1062 RegisterID* temp = generator.emitNode(m_expr2); |
|
1063 if (fallThroughMeansTrue) |
|
1064 generator.emitJumpIfFalse(temp, falseTarget); |
|
1065 else |
|
1066 generator.emitJumpIfTrue(temp, trueTarget); |
|
1067 } |
|
1068 } |
|
1069 |
|
1070 // ------------------------------ ConditionalNode ------------------------------ |
|
1071 |
|
1072 RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1073 { |
|
1074 RefPtr<RegisterID> newDst = generator.finalDestination(dst); |
|
1075 RefPtr<Label> beforeElse = generator.newLabel(); |
|
1076 RefPtr<Label> afterElse = generator.newLabel(); |
|
1077 |
|
1078 if (m_logical->hasConditionContextCodegen()) { |
|
1079 RefPtr<Label> beforeThen = generator.newLabel(); |
|
1080 generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), true); |
|
1081 generator.emitLabel(beforeThen.get()); |
|
1082 } else { |
|
1083 RegisterID* cond = generator.emitNode(m_logical); |
|
1084 generator.emitJumpIfFalse(cond, beforeElse.get()); |
|
1085 } |
|
1086 |
|
1087 generator.emitNode(newDst.get(), m_expr1); |
|
1088 generator.emitJump(afterElse.get()); |
|
1089 |
|
1090 generator.emitLabel(beforeElse.get()); |
|
1091 generator.emitNode(newDst.get(), m_expr2); |
|
1092 |
|
1093 generator.emitLabel(afterElse.get()); |
|
1094 |
|
1095 return newDst.get(); |
|
1096 } |
|
1097 |
|
1098 // ------------------------------ ReadModifyResolveNode ----------------------------------- |
|
1099 |
|
1100 // FIXME: should this be moved to be a method on BytecodeGenerator? |
|
1101 static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) |
|
1102 { |
|
1103 OpcodeID opcodeID; |
|
1104 switch (oper) { |
|
1105 case OpMultEq: |
|
1106 opcodeID = op_mul; |
|
1107 break; |
|
1108 case OpDivEq: |
|
1109 opcodeID = op_div; |
|
1110 break; |
|
1111 case OpPlusEq: |
|
1112 if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) |
|
1113 return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); |
|
1114 opcodeID = op_add; |
|
1115 break; |
|
1116 case OpMinusEq: |
|
1117 opcodeID = op_sub; |
|
1118 break; |
|
1119 case OpLShift: |
|
1120 opcodeID = op_lshift; |
|
1121 break; |
|
1122 case OpRShift: |
|
1123 opcodeID = op_rshift; |
|
1124 break; |
|
1125 case OpURShift: |
|
1126 opcodeID = op_urshift; |
|
1127 break; |
|
1128 case OpAndEq: |
|
1129 opcodeID = op_bitand; |
|
1130 break; |
|
1131 case OpXOrEq: |
|
1132 opcodeID = op_bitxor; |
|
1133 break; |
|
1134 case OpOrEq: |
|
1135 opcodeID = op_bitor; |
|
1136 break; |
|
1137 case OpModEq: |
|
1138 opcodeID = op_mod; |
|
1139 break; |
|
1140 default: |
|
1141 ASSERT_NOT_REACHED(); |
|
1142 return dst; |
|
1143 } |
|
1144 |
|
1145 RegisterID* src2 = generator.emitNode(m_right); |
|
1146 |
|
1147 // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. |
|
1148 // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. |
|
1149 if (emitExpressionInfoForMe) |
|
1150 generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); |
|
1151 |
|
1152 return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); |
|
1153 } |
|
1154 |
|
1155 RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1156 { |
|
1157 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
1158 if (generator.isLocalConstant(m_ident)) { |
|
1159 return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1160 } |
|
1161 |
|
1162 if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { |
|
1163 RefPtr<RegisterID> result = generator.newTemporary(); |
|
1164 generator.emitMove(result.get(), local); |
|
1165 emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1166 generator.emitMove(local, result.get()); |
|
1167 return generator.moveToDestinationIfNeeded(dst, result.get()); |
|
1168 } |
|
1169 |
|
1170 RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1171 return generator.moveToDestinationIfNeeded(dst, result); |
|
1172 } |
|
1173 |
|
1174 int index = 0; |
|
1175 size_t depth = 0; |
|
1176 JSObject* globalObject = 0; |
|
1177 bool requiresDynamicChecks = false; |
|
1178 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { |
|
1179 RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); |
|
1180 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1181 generator.emitPutScopedVar(depth, index, result, globalObject); |
|
1182 return result; |
|
1183 } |
|
1184 |
|
1185 RefPtr<RegisterID> src1 = generator.tempDestination(dst); |
|
1186 generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); |
|
1187 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); |
|
1188 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); |
|
1189 return generator.emitPutById(base.get(), m_ident, result); |
|
1190 } |
|
1191 |
|
1192 // ------------------------------ AssignResolveNode ----------------------------------- |
|
1193 |
|
1194 RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1195 { |
|
1196 if (RegisterID* local = generator.registerFor(m_ident)) { |
|
1197 if (generator.isLocalConstant(m_ident)) |
|
1198 return generator.emitNode(dst, m_right); |
|
1199 |
|
1200 RegisterID* result = generator.emitNode(local, m_right); |
|
1201 return generator.moveToDestinationIfNeeded(dst, result); |
|
1202 } |
|
1203 |
|
1204 int index = 0; |
|
1205 size_t depth = 0; |
|
1206 JSObject* globalObject = 0; |
|
1207 bool requiresDynamicChecks = false; |
|
1208 if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { |
|
1209 if (dst == generator.ignoredResult()) |
|
1210 dst = 0; |
|
1211 RegisterID* value = generator.emitNode(dst, m_right); |
|
1212 generator.emitPutScopedVar(depth, index, value, globalObject); |
|
1213 return value; |
|
1214 } |
|
1215 |
|
1216 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); |
|
1217 if (dst == generator.ignoredResult()) |
|
1218 dst = 0; |
|
1219 RegisterID* value = generator.emitNode(dst, m_right); |
|
1220 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1221 return generator.emitPutById(base.get(), m_ident, value); |
|
1222 } |
|
1223 |
|
1224 // ------------------------------ AssignDotNode ----------------------------------- |
|
1225 |
|
1226 RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1227 { |
|
1228 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); |
|
1229 RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); |
|
1230 RegisterID* result = generator.emitNode(value.get(), m_right); |
|
1231 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1232 generator.emitPutById(base.get(), m_ident, result); |
|
1233 return generator.moveToDestinationIfNeeded(dst, result); |
|
1234 } |
|
1235 |
|
1236 // ------------------------------ ReadModifyDotNode ----------------------------------- |
|
1237 |
|
1238 RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1239 { |
|
1240 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); |
|
1241 |
|
1242 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
1243 RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
|
1244 RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1245 |
|
1246 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1247 return generator.emitPutById(base.get(), m_ident, updatedValue); |
|
1248 } |
|
1249 |
|
1250 // ------------------------------ AssignErrorNode ----------------------------------- |
|
1251 |
|
1252 RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
1253 { |
|
1254 return emitThrowError(generator, true, "Left side of assignment is not a reference."); |
|
1255 } |
|
1256 |
|
1257 // ------------------------------ AssignBracketNode ----------------------------------- |
|
1258 |
|
1259 RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1260 { |
|
1261 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); |
|
1262 RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); |
|
1263 RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); |
|
1264 RegisterID* result = generator.emitNode(value.get(), m_right); |
|
1265 |
|
1266 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1267 generator.emitPutByVal(base.get(), property.get(), result); |
|
1268 return generator.moveToDestinationIfNeeded(dst, result); |
|
1269 } |
|
1270 |
|
1271 // ------------------------------ ReadModifyBracketNode ----------------------------------- |
|
1272 |
|
1273 RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1274 { |
|
1275 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); |
|
1276 RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); |
|
1277 |
|
1278 generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); |
|
1279 RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
|
1280 RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
|
1281 |
|
1282 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1283 generator.emitPutByVal(base.get(), property.get(), updatedValue); |
|
1284 |
|
1285 return updatedValue; |
|
1286 } |
|
1287 |
|
1288 // ------------------------------ CommaNode ------------------------------------ |
|
1289 |
|
1290 RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1291 { |
|
1292 ASSERT(m_expressions.size() > 1); |
|
1293 for (size_t i = 0; i < m_expressions.size() - 1; i++) |
|
1294 generator.emitNode(generator.ignoredResult(), m_expressions[i]); |
|
1295 return generator.emitNode(dst, m_expressions.last()); |
|
1296 } |
|
1297 |
|
1298 // ------------------------------ ConstDeclNode ------------------------------------ |
|
1299 |
|
1300 RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) |
|
1301 { |
|
1302 if (RegisterID* local = generator.constRegisterFor(m_ident)) { |
|
1303 if (!m_init) |
|
1304 return local; |
|
1305 |
|
1306 return generator.emitNode(local, m_init); |
|
1307 } |
|
1308 |
|
1309 if (generator.codeType() != EvalCode) { |
|
1310 if (m_init) |
|
1311 return generator.emitNode(m_init); |
|
1312 else |
|
1313 return generator.emitResolve(generator.newTemporary(), m_ident); |
|
1314 } |
|
1315 // FIXME: While this code should only be hit in eval code, it will potentially |
|
1316 // assign to the wrong base if m_ident exists in an intervening dynamic scope. |
|
1317 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); |
|
1318 RegisterID* value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); |
|
1319 return generator.emitPutById(base.get(), m_ident, value); |
|
1320 } |
|
1321 |
|
1322 RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
1323 { |
|
1324 RegisterID* result = 0; |
|
1325 for (ConstDeclNode* n = this; n; n = n->m_next) |
|
1326 result = n->emitCodeSingle(generator); |
|
1327 |
|
1328 return result; |
|
1329 } |
|
1330 |
|
1331 // ------------------------------ ConstStatementNode ----------------------------- |
|
1332 |
|
1333 RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
1334 { |
|
1335 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1336 return generator.emitNode(m_next); |
|
1337 } |
|
1338 |
|
1339 // ------------------------------ SourceElements ------------------------------- |
|
1340 |
|
1341 |
|
1342 inline StatementNode* SourceElements::lastStatement() const |
|
1343 { |
|
1344 size_t size = m_statements.size(); |
|
1345 return size ? m_statements[size - 1] : 0; |
|
1346 } |
|
1347 |
|
1348 inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1349 { |
|
1350 size_t size = m_statements.size(); |
|
1351 for (size_t i = 0; i < size; ++i) |
|
1352 generator.emitNode(dst, m_statements[i]); |
|
1353 } |
|
1354 |
|
1355 // ------------------------------ BlockNode ------------------------------------ |
|
1356 |
|
1357 inline StatementNode* BlockNode::lastStatement() const |
|
1358 { |
|
1359 return m_statements ? m_statements->lastStatement() : 0; |
|
1360 } |
|
1361 |
|
1362 inline StatementNode* BlockNode::singleStatement() const |
|
1363 { |
|
1364 return m_statements ? m_statements->singleStatement() : 0; |
|
1365 } |
|
1366 |
|
1367 RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1368 { |
|
1369 if (m_statements) |
|
1370 m_statements->emitBytecode(generator, dst); |
|
1371 return 0; |
|
1372 } |
|
1373 |
|
1374 // ------------------------------ EmptyStatementNode --------------------------- |
|
1375 |
|
1376 RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1377 { |
|
1378 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1379 return dst; |
|
1380 } |
|
1381 |
|
1382 // ------------------------------ DebuggerStatementNode --------------------------- |
|
1383 |
|
1384 RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1385 { |
|
1386 generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); |
|
1387 return dst; |
|
1388 } |
|
1389 |
|
1390 // ------------------------------ ExprStatementNode ---------------------------- |
|
1391 |
|
1392 RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1393 { |
|
1394 ASSERT(m_expr); |
|
1395 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1396 return generator.emitNode(dst, m_expr); |
|
1397 } |
|
1398 |
|
1399 // ------------------------------ VarStatementNode ---------------------------- |
|
1400 |
|
1401 RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
1402 { |
|
1403 ASSERT(m_expr); |
|
1404 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1405 return generator.emitNode(m_expr); |
|
1406 } |
|
1407 |
|
1408 // ------------------------------ IfNode --------------------------------------- |
|
1409 |
|
1410 RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1411 { |
|
1412 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1413 |
|
1414 RefPtr<Label> afterThen = generator.newLabel(); |
|
1415 |
|
1416 if (m_condition->hasConditionContextCodegen()) { |
|
1417 RefPtr<Label> beforeThen = generator.newLabel(); |
|
1418 generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), true); |
|
1419 generator.emitLabel(beforeThen.get()); |
|
1420 } else { |
|
1421 RegisterID* cond = generator.emitNode(m_condition); |
|
1422 generator.emitJumpIfFalse(cond, afterThen.get()); |
|
1423 } |
|
1424 |
|
1425 generator.emitNode(dst, m_ifBlock); |
|
1426 generator.emitLabel(afterThen.get()); |
|
1427 |
|
1428 // FIXME: This should return the last statement executed so that it can be returned as a Completion. |
|
1429 return 0; |
|
1430 } |
|
1431 |
|
1432 // ------------------------------ IfElseNode --------------------------------------- |
|
1433 |
|
1434 RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1435 { |
|
1436 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1437 |
|
1438 RefPtr<Label> beforeElse = generator.newLabel(); |
|
1439 RefPtr<Label> afterElse = generator.newLabel(); |
|
1440 |
|
1441 if (m_condition->hasConditionContextCodegen()) { |
|
1442 RefPtr<Label> beforeThen = generator.newLabel(); |
|
1443 generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), true); |
|
1444 generator.emitLabel(beforeThen.get()); |
|
1445 } else { |
|
1446 RegisterID* cond = generator.emitNode(m_condition); |
|
1447 generator.emitJumpIfFalse(cond, beforeElse.get()); |
|
1448 } |
|
1449 |
|
1450 generator.emitNode(dst, m_ifBlock); |
|
1451 generator.emitJump(afterElse.get()); |
|
1452 |
|
1453 generator.emitLabel(beforeElse.get()); |
|
1454 |
|
1455 generator.emitNode(dst, m_elseBlock); |
|
1456 |
|
1457 generator.emitLabel(afterElse.get()); |
|
1458 |
|
1459 // FIXME: This should return the last statement executed so that it can be returned as a Completion. |
|
1460 return 0; |
|
1461 } |
|
1462 |
|
1463 // ------------------------------ DoWhileNode ---------------------------------- |
|
1464 |
|
1465 RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1466 { |
|
1467 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
|
1468 |
|
1469 RefPtr<Label> topOfLoop = generator.newLabel(); |
|
1470 generator.emitLabel(topOfLoop.get()); |
|
1471 |
|
1472 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1473 |
|
1474 RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); |
|
1475 |
|
1476 generator.emitLabel(scope->continueTarget()); |
|
1477 generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); |
|
1478 if (m_expr->hasConditionContextCodegen()) |
|
1479 generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); |
|
1480 else { |
|
1481 RegisterID* cond = generator.emitNode(m_expr); |
|
1482 generator.emitJumpIfTrue(cond, topOfLoop.get()); |
|
1483 } |
|
1484 |
|
1485 generator.emitLabel(scope->breakTarget()); |
|
1486 return result.get(); |
|
1487 } |
|
1488 |
|
1489 // ------------------------------ WhileNode ------------------------------------ |
|
1490 |
|
1491 RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1492 { |
|
1493 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
|
1494 |
|
1495 generator.emitJump(scope->continueTarget()); |
|
1496 |
|
1497 RefPtr<Label> topOfLoop = generator.newLabel(); |
|
1498 generator.emitLabel(topOfLoop.get()); |
|
1499 |
|
1500 generator.emitNode(dst, m_statement); |
|
1501 |
|
1502 generator.emitLabel(scope->continueTarget()); |
|
1503 generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); |
|
1504 |
|
1505 if (m_expr->hasConditionContextCodegen()) |
|
1506 generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); |
|
1507 else { |
|
1508 RegisterID* cond = generator.emitNode(m_expr); |
|
1509 generator.emitJumpIfTrue(cond, topOfLoop.get()); |
|
1510 } |
|
1511 |
|
1512 generator.emitLabel(scope->breakTarget()); |
|
1513 |
|
1514 // FIXME: This should return the last statement executed so that it can be returned as a Completion |
|
1515 return 0; |
|
1516 } |
|
1517 |
|
1518 // ------------------------------ ForNode -------------------------------------- |
|
1519 |
|
1520 RegisterID* ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1521 { |
|
1522 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
|
1523 |
|
1524 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1525 |
|
1526 if (m_expr1) |
|
1527 generator.emitNode(generator.ignoredResult(), m_expr1); |
|
1528 |
|
1529 RefPtr<Label> condition = generator.newLabel(); |
|
1530 generator.emitJump(condition.get()); |
|
1531 |
|
1532 RefPtr<Label> topOfLoop = generator.newLabel(); |
|
1533 generator.emitLabel(topOfLoop.get()); |
|
1534 |
|
1535 RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); |
|
1536 |
|
1537 generator.emitLabel(scope->continueTarget()); |
|
1538 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1539 if (m_expr3) |
|
1540 generator.emitNode(generator.ignoredResult(), m_expr3); |
|
1541 |
|
1542 generator.emitLabel(condition.get()); |
|
1543 if (m_expr2) { |
|
1544 if (m_expr2->hasConditionContextCodegen()) |
|
1545 generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), false); |
|
1546 else { |
|
1547 RegisterID* cond = generator.emitNode(m_expr2); |
|
1548 generator.emitJumpIfTrue(cond, topOfLoop.get()); |
|
1549 } |
|
1550 } else |
|
1551 generator.emitJump(topOfLoop.get()); |
|
1552 |
|
1553 generator.emitLabel(scope->breakTarget()); |
|
1554 return result.get(); |
|
1555 } |
|
1556 |
|
1557 // ------------------------------ ForInNode ------------------------------------ |
|
1558 |
|
1559 RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1560 { |
|
1561 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
|
1562 |
|
1563 if (!m_lexpr->isLocation()) |
|
1564 return emitThrowError(generator, true, "Left side of for-in statement is not a reference."); |
|
1565 |
|
1566 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1567 |
|
1568 if (m_init) |
|
1569 generator.emitNode(generator.ignoredResult(), m_init); |
|
1570 |
|
1571 RefPtr<RegisterID> base = generator.newTemporary(); |
|
1572 generator.emitNode(base.get(), m_expr); |
|
1573 RefPtr<RegisterID> i = generator.newTemporary(); |
|
1574 RefPtr<RegisterID> size = generator.newTemporary(); |
|
1575 RefPtr<RegisterID> expectedSubscript; |
|
1576 RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget()); |
|
1577 generator.emitJump(scope->continueTarget()); |
|
1578 |
|
1579 RefPtr<Label> loopStart = generator.newLabel(); |
|
1580 generator.emitLabel(loopStart.get()); |
|
1581 |
|
1582 RegisterID* propertyName; |
|
1583 bool optimizedForinAccess = false; |
|
1584 if (m_lexpr->isResolveNode()) { |
|
1585 const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); |
|
1586 propertyName = generator.registerFor(ident); |
|
1587 if (!propertyName) { |
|
1588 propertyName = generator.newTemporary(); |
|
1589 RefPtr<RegisterID> protect = propertyName; |
|
1590 RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); |
|
1591 |
|
1592 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1593 generator.emitPutById(base, ident, propertyName); |
|
1594 } else { |
|
1595 expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); |
|
1596 generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName); |
|
1597 optimizedForinAccess = true; |
|
1598 } |
|
1599 } else if (m_lexpr->isDotAccessorNode()) { |
|
1600 DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); |
|
1601 const Identifier& ident = assignNode->identifier(); |
|
1602 propertyName = generator.newTemporary(); |
|
1603 RefPtr<RegisterID> protect = propertyName; |
|
1604 RegisterID* base = generator.emitNode(assignNode->base()); |
|
1605 |
|
1606 generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); |
|
1607 generator.emitPutById(base, ident, propertyName); |
|
1608 } else { |
|
1609 ASSERT(m_lexpr->isBracketAccessorNode()); |
|
1610 BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); |
|
1611 propertyName = generator.newTemporary(); |
|
1612 RefPtr<RegisterID> protect = propertyName; |
|
1613 RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
|
1614 RegisterID* subscript = generator.emitNode(assignNode->subscript()); |
|
1615 |
|
1616 generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); |
|
1617 generator.emitPutByVal(base.get(), subscript, propertyName); |
|
1618 } |
|
1619 |
|
1620 generator.emitNode(dst, m_statement); |
|
1621 |
|
1622 if (optimizedForinAccess) |
|
1623 generator.popOptimisedForIn(); |
|
1624 |
|
1625 generator.emitLabel(scope->continueTarget()); |
|
1626 generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); |
|
1627 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1628 generator.emitLabel(scope->breakTarget()); |
|
1629 return dst; |
|
1630 } |
|
1631 |
|
1632 // ------------------------------ ContinueNode --------------------------------- |
|
1633 |
|
1634 // ECMA 12.7 |
|
1635 RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1636 { |
|
1637 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1638 |
|
1639 LabelScope* scope = generator.continueTarget(m_ident); |
|
1640 |
|
1641 if (!scope) |
|
1642 return m_ident.isEmpty() |
|
1643 ? emitThrowError(generator, false, "Invalid continue statement.") |
|
1644 : emitThrowError(generator, false, "Undefined label: '%s'.", m_ident); |
|
1645 |
|
1646 generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); |
|
1647 return dst; |
|
1648 } |
|
1649 |
|
1650 // ------------------------------ BreakNode ------------------------------------ |
|
1651 |
|
1652 // ECMA 12.8 |
|
1653 RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1654 { |
|
1655 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1656 |
|
1657 LabelScope* scope = generator.breakTarget(m_ident); |
|
1658 |
|
1659 if (!scope) |
|
1660 return m_ident.isEmpty() |
|
1661 ? emitThrowError(generator, false, "Invalid break statement.") |
|
1662 : emitThrowError(generator, false, "Undefined label: '%s'.", m_ident); |
|
1663 |
|
1664 generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); |
|
1665 return dst; |
|
1666 } |
|
1667 |
|
1668 // ------------------------------ ReturnNode ----------------------------------- |
|
1669 |
|
1670 RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1671 { |
|
1672 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1673 if (generator.codeType() != FunctionCode) |
|
1674 return emitThrowError(generator, false, "Invalid return statement."); |
|
1675 |
|
1676 if (dst == generator.ignoredResult()) |
|
1677 dst = 0; |
|
1678 RegisterID* r0 = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); |
|
1679 RefPtr<RegisterID> returnRegister; |
|
1680 if (generator.scopeDepth()) { |
|
1681 RefPtr<Label> l0 = generator.newLabel(); |
|
1682 if (generator.hasFinaliser() && !r0->isTemporary()) { |
|
1683 returnRegister = generator.emitMove(generator.newTemporary(), r0); |
|
1684 r0 = returnRegister.get(); |
|
1685 } |
|
1686 generator.emitJumpScopes(l0.get(), 0); |
|
1687 generator.emitLabel(l0.get()); |
|
1688 } |
|
1689 generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); |
|
1690 return generator.emitReturn(r0); |
|
1691 } |
|
1692 |
|
1693 // ------------------------------ WithNode ------------------------------------- |
|
1694 |
|
1695 RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1696 { |
|
1697 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1698 |
|
1699 RefPtr<RegisterID> scope = generator.newTemporary(); |
|
1700 generator.emitNode(scope.get(), m_expr); // scope must be protected until popped |
|
1701 generator.emitExpressionInfo(m_divot, m_expressionLength, 0); |
|
1702 generator.emitPushScope(scope.get()); |
|
1703 RegisterID* result = generator.emitNode(dst, m_statement); |
|
1704 generator.emitPopScope(); |
|
1705 return result; |
|
1706 } |
|
1707 |
|
1708 // ------------------------------ CaseClauseNode -------------------------------- |
|
1709 |
|
1710 inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1711 { |
|
1712 if (m_statements) |
|
1713 m_statements->emitBytecode(generator, dst); |
|
1714 } |
|
1715 |
|
1716 // ------------------------------ CaseBlockNode -------------------------------- |
|
1717 |
|
1718 enum SwitchKind { |
|
1719 SwitchUnset = 0, |
|
1720 SwitchNumber = 1, |
|
1721 SwitchString = 2, |
|
1722 SwitchNeither = 3 |
|
1723 }; |
|
1724 |
|
1725 static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) |
|
1726 { |
|
1727 for (; list; list = list->getNext()) { |
|
1728 ExpressionNode* clauseExpression = list->getClause()->expr(); |
|
1729 literalVector.append(clauseExpression); |
|
1730 if (clauseExpression->isNumber()) { |
|
1731 double value = static_cast<NumberNode*>(clauseExpression)->value(); |
|
1732 int32_t intVal = static_cast<int32_t>(value); |
|
1733 if ((typeForTable & ~SwitchNumber) || (intVal != value)) { |
|
1734 typeForTable = SwitchNeither; |
|
1735 break; |
|
1736 } |
|
1737 if (intVal < min_num) |
|
1738 min_num = intVal; |
|
1739 if (intVal > max_num) |
|
1740 max_num = intVal; |
|
1741 typeForTable = SwitchNumber; |
|
1742 continue; |
|
1743 } |
|
1744 if (clauseExpression->isString()) { |
|
1745 if (typeForTable & ~SwitchString) { |
|
1746 typeForTable = SwitchNeither; |
|
1747 break; |
|
1748 } |
|
1749 const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring(); |
|
1750 if (singleCharacterSwitch &= value.size() == 1) { |
|
1751 int32_t intVal = value.rep()->characters()[0]; |
|
1752 if (intVal < min_num) |
|
1753 min_num = intVal; |
|
1754 if (intVal > max_num) |
|
1755 max_num = intVal; |
|
1756 } |
|
1757 typeForTable = SwitchString; |
|
1758 continue; |
|
1759 } |
|
1760 typeForTable = SwitchNeither; |
|
1761 break; |
|
1762 } |
|
1763 } |
|
1764 |
|
1765 SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) |
|
1766 { |
|
1767 SwitchKind typeForTable = SwitchUnset; |
|
1768 bool singleCharacterSwitch = true; |
|
1769 |
|
1770 processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); |
|
1771 processClauseList(m_list2, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); |
|
1772 |
|
1773 if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) |
|
1774 return SwitchInfo::SwitchNone; |
|
1775 |
|
1776 if (typeForTable == SwitchNumber) { |
|
1777 int32_t range = max_num - min_num; |
|
1778 if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) |
|
1779 return SwitchInfo::SwitchImmediate; |
|
1780 return SwitchInfo::SwitchNone; |
|
1781 } |
|
1782 |
|
1783 ASSERT(typeForTable == SwitchString); |
|
1784 |
|
1785 if (singleCharacterSwitch) { |
|
1786 int32_t range = max_num - min_num; |
|
1787 if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) |
|
1788 return SwitchInfo::SwitchCharacter; |
|
1789 } |
|
1790 |
|
1791 return SwitchInfo::SwitchString; |
|
1792 } |
|
1793 |
|
1794 RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) |
|
1795 { |
|
1796 RefPtr<Label> defaultLabel; |
|
1797 Vector<RefPtr<Label>, 8> labelVector; |
|
1798 Vector<ExpressionNode*, 8> literalVector; |
|
1799 int32_t min_num = std::numeric_limits<int32_t>::max(); |
|
1800 int32_t max_num = std::numeric_limits<int32_t>::min(); |
|
1801 SwitchInfo::SwitchType switchType = tryOptimizedSwitch(literalVector, min_num, max_num); |
|
1802 |
|
1803 if (switchType != SwitchInfo::SwitchNone) { |
|
1804 // Prepare the various labels |
|
1805 for (uint32_t i = 0; i < literalVector.size(); i++) |
|
1806 labelVector.append(generator.newLabel()); |
|
1807 defaultLabel = generator.newLabel(); |
|
1808 generator.beginSwitch(switchExpression, switchType); |
|
1809 } else { |
|
1810 // Setup jumps |
|
1811 for (ClauseListNode* list = m_list1; list; list = list->getNext()) { |
|
1812 RefPtr<RegisterID> clauseVal = generator.newTemporary(); |
|
1813 generator.emitNode(clauseVal.get(), list->getClause()->expr()); |
|
1814 generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); |
|
1815 labelVector.append(generator.newLabel()); |
|
1816 generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); |
|
1817 } |
|
1818 |
|
1819 for (ClauseListNode* list = m_list2; list; list = list->getNext()) { |
|
1820 RefPtr<RegisterID> clauseVal = generator.newTemporary(); |
|
1821 generator.emitNode(clauseVal.get(), list->getClause()->expr()); |
|
1822 generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); |
|
1823 labelVector.append(generator.newLabel()); |
|
1824 generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); |
|
1825 } |
|
1826 defaultLabel = generator.newLabel(); |
|
1827 generator.emitJump(defaultLabel.get()); |
|
1828 } |
|
1829 |
|
1830 RegisterID* result = 0; |
|
1831 |
|
1832 size_t i = 0; |
|
1833 for (ClauseListNode* list = m_list1; list; list = list->getNext()) { |
|
1834 generator.emitLabel(labelVector[i++].get()); |
|
1835 list->getClause()->emitBytecode(generator, dst); |
|
1836 } |
|
1837 |
|
1838 if (m_defaultClause) { |
|
1839 generator.emitLabel(defaultLabel.get()); |
|
1840 m_defaultClause->emitBytecode(generator, dst); |
|
1841 } |
|
1842 |
|
1843 for (ClauseListNode* list = m_list2; list; list = list->getNext()) { |
|
1844 generator.emitLabel(labelVector[i++].get()); |
|
1845 list->getClause()->emitBytecode(generator, dst); |
|
1846 } |
|
1847 if (!m_defaultClause) |
|
1848 generator.emitLabel(defaultLabel.get()); |
|
1849 |
|
1850 ASSERT(i == labelVector.size()); |
|
1851 if (switchType != SwitchInfo::SwitchNone) { |
|
1852 ASSERT(labelVector.size() == literalVector.size()); |
|
1853 generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); |
|
1854 } |
|
1855 return result; |
|
1856 } |
|
1857 |
|
1858 // ------------------------------ SwitchNode ----------------------------------- |
|
1859 |
|
1860 RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1861 { |
|
1862 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1863 |
|
1864 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); |
|
1865 |
|
1866 RefPtr<RegisterID> r0 = generator.emitNode(m_expr); |
|
1867 RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); |
|
1868 |
|
1869 generator.emitLabel(scope->breakTarget()); |
|
1870 return r1; |
|
1871 } |
|
1872 |
|
1873 // ------------------------------ LabelNode ------------------------------------ |
|
1874 |
|
1875 RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1876 { |
|
1877 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1878 |
|
1879 if (generator.breakTarget(m_name)) |
|
1880 return emitThrowError(generator, false, "Duplicate label: %s.", m_name); |
|
1881 |
|
1882 RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); |
|
1883 RegisterID* r0 = generator.emitNode(dst, m_statement); |
|
1884 |
|
1885 generator.emitLabel(scope->breakTarget()); |
|
1886 return r0; |
|
1887 } |
|
1888 |
|
1889 // ------------------------------ ThrowNode ------------------------------------ |
|
1890 |
|
1891 RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1892 { |
|
1893 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1894 |
|
1895 if (dst == generator.ignoredResult()) |
|
1896 dst = 0; |
|
1897 RefPtr<RegisterID> expr = generator.emitNode(m_expr); |
|
1898 generator.emitExpressionInfo(divot(), startOffset(), endOffset()); |
|
1899 generator.emitThrow(expr.get()); |
|
1900 return 0; |
|
1901 } |
|
1902 |
|
1903 // ------------------------------ TryNode -------------------------------------- |
|
1904 |
|
1905 RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1906 { |
|
1907 // NOTE: The catch and finally blocks must be labeled explicitly, so the |
|
1908 // optimizer knows they may be jumped to from anywhere. |
|
1909 |
|
1910 generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); |
|
1911 |
|
1912 RefPtr<Label> tryStartLabel = generator.newLabel(); |
|
1913 RefPtr<Label> finallyStart; |
|
1914 RefPtr<RegisterID> finallyReturnAddr; |
|
1915 if (m_finallyBlock) { |
|
1916 finallyStart = generator.newLabel(); |
|
1917 finallyReturnAddr = generator.newTemporary(); |
|
1918 generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get()); |
|
1919 } |
|
1920 |
|
1921 generator.emitLabel(tryStartLabel.get()); |
|
1922 generator.emitNode(dst, m_tryBlock); |
|
1923 |
|
1924 if (m_catchBlock) { |
|
1925 RefPtr<Label> catchEndLabel = generator.newLabel(); |
|
1926 |
|
1927 // Normal path: jump over the catch block. |
|
1928 generator.emitJump(catchEndLabel.get()); |
|
1929 |
|
1930 // Uncaught exception path: the catch block. |
|
1931 RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); |
|
1932 RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); |
|
1933 if (m_catchHasEval) { |
|
1934 RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); |
|
1935 generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); |
|
1936 generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); |
|
1937 generator.emitPushScope(exceptionRegister.get()); |
|
1938 } else |
|
1939 generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); |
|
1940 generator.emitNode(dst, m_catchBlock); |
|
1941 generator.emitPopScope(); |
|
1942 generator.emitLabel(catchEndLabel.get()); |
|
1943 } |
|
1944 |
|
1945 if (m_finallyBlock) { |
|
1946 generator.popFinallyContext(); |
|
1947 // there may be important registers live at the time we jump |
|
1948 // to a finally block (such as for a return or throw) so we |
|
1949 // ref the highest register ever used as a conservative |
|
1950 // approach to not clobbering anything important |
|
1951 RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister(); |
|
1952 RefPtr<Label> finallyEndLabel = generator.newLabel(); |
|
1953 |
|
1954 // Normal path: invoke the finally block, then jump over it. |
|
1955 generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); |
|
1956 generator.emitJump(finallyEndLabel.get()); |
|
1957 |
|
1958 // Uncaught exception path: invoke the finally block, then re-throw the exception. |
|
1959 RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); |
|
1960 RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); |
|
1961 generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); |
|
1962 generator.emitThrow(tempExceptionRegister.get()); |
|
1963 |
|
1964 // The finally block. |
|
1965 generator.emitLabel(finallyStart.get()); |
|
1966 generator.emitNode(dst, m_finallyBlock); |
|
1967 generator.emitSubroutineReturn(finallyReturnAddr.get()); |
|
1968 |
|
1969 generator.emitLabel(finallyEndLabel.get()); |
|
1970 } |
|
1971 |
|
1972 return dst; |
|
1973 } |
|
1974 |
|
1975 // ------------------------------ ScopeNode ----------------------------- |
|
1976 |
|
1977 inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
1978 { |
|
1979 if (m_data->m_statements) |
|
1980 m_data->m_statements->emitBytecode(generator, dst); |
|
1981 } |
|
1982 |
|
1983 // ------------------------------ ProgramNode ----------------------------- |
|
1984 |
|
1985 RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
1986 { |
|
1987 generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); |
|
1988 |
|
1989 RefPtr<RegisterID> dstRegister = generator.newTemporary(); |
|
1990 generator.emitLoad(dstRegister.get(), jsUndefined()); |
|
1991 emitStatementsBytecode(generator, dstRegister.get()); |
|
1992 |
|
1993 generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); |
|
1994 generator.emitEnd(dstRegister.get()); |
|
1995 return 0; |
|
1996 } |
|
1997 |
|
1998 // ------------------------------ EvalNode ----------------------------- |
|
1999 |
|
2000 RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
2001 { |
|
2002 generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); |
|
2003 |
|
2004 RefPtr<RegisterID> dstRegister = generator.newTemporary(); |
|
2005 generator.emitLoad(dstRegister.get(), jsUndefined()); |
|
2006 emitStatementsBytecode(generator, dstRegister.get()); |
|
2007 |
|
2008 generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); |
|
2009 generator.emitEnd(dstRegister.get()); |
|
2010 return 0; |
|
2011 } |
|
2012 |
|
2013 // ------------------------------ FunctionBodyNode ----------------------------- |
|
2014 |
|
2015 RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
|
2016 { |
|
2017 generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); |
|
2018 emitStatementsBytecode(generator, generator.ignoredResult()); |
|
2019 |
|
2020 StatementNode* singleStatement = this->singleStatement(); |
|
2021 ReturnNode* returnNode = 0; |
|
2022 |
|
2023 // Check for a return statement at the end of a function composed of a single block. |
|
2024 if (singleStatement && singleStatement->isBlock()) { |
|
2025 StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); |
|
2026 if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) |
|
2027 returnNode = static_cast<ReturnNode*>(lastStatementInBlock); |
|
2028 } |
|
2029 |
|
2030 // If there is no return we must automatically insert one. |
|
2031 if (!returnNode) { |
|
2032 RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); |
|
2033 generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); |
|
2034 generator.emitReturn(r0); |
|
2035 return 0; |
|
2036 } |
|
2037 |
|
2038 // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare. |
|
2039 if (static_cast<BlockNode*>(singleStatement)->singleStatement()) { |
|
2040 ExpressionNode* returnValueExpression = returnNode->value(); |
|
2041 if (returnValueExpression && returnValueExpression->isSubtract()) { |
|
2042 ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs(); |
|
2043 ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs(); |
|
2044 if (lhsExpression->isResolveNode() && rhsExpression->isResolveNode()) { |
|
2045 generator.setIsNumericCompareFunction(generator.argumentNumberFor(static_cast<ResolveNode*>(lhsExpression)->identifier()) == 1 |
|
2046 && generator.argumentNumberFor(static_cast<ResolveNode*>(rhsExpression)->identifier()) == 2); |
|
2047 } |
|
2048 } |
|
2049 } |
|
2050 |
|
2051 return 0; |
|
2052 } |
|
2053 |
|
2054 // ------------------------------ FuncDeclNode --------------------------------- |
|
2055 |
|
2056 RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
2057 { |
|
2058 if (dst == generator.ignoredResult()) |
|
2059 dst = 0; |
|
2060 return dst; |
|
2061 } |
|
2062 |
|
2063 // ------------------------------ FuncExprNode --------------------------------- |
|
2064 |
|
2065 RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
|
2066 { |
|
2067 return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); |
|
2068 } |
|
2069 |
|
2070 } // namespace JSC |