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, 2012 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>
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.
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.
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.
28 #include "NodeConstructors.h"
30 #include "BytecodeGenerator.h"
31 #include "CallFrame.h"
34 #include "JSFunction.h"
35 #include "JSGlobalObject.h"
36 #include "JSStaticScopeObject.h"
37 #include "LabelScope.h"
39 #include "Operations.h"
41 #include "PropertyNameArray.h"
42 #include "RegExpCache.h"
43 #include "RegExpObject.h"
44 #include "SamplingTool.h"
45 #include "UStringConcatenate.h"
46 #include <wtf/Assertions.h>
47 #include <wtf/RefCountedLeakCounter.h>
48 #include <wtf/Threading.h>
55 Details of the emitBytecode function.
57 Return value: The register holding the production's value.
58 dst: An optional parameter specifying the most efficient destination at
59 which to store the production's value. The callee must honor dst.
61 The dst argument provides for a crude form of copy propagation. For example,
74 because the assignment node, "x =", passes r[x] as dst to the number node, "1".
77 // ------------------------------ ThrowableExpressionData --------------------------------
79 RegisterID
* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator
& generator
, const UString
& message
)
81 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
82 generator
.emitThrowReferenceError(message
);
83 return generator
.newTemporary();
86 // ------------------------------ NullNode -------------------------------------
88 RegisterID
* NullNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
90 if (dst
== generator
.ignoredResult())
92 return generator
.emitLoad(dst
, jsNull());
95 // ------------------------------ BooleanNode ----------------------------------
97 RegisterID
* BooleanNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
99 if (dst
== generator
.ignoredResult())
101 return generator
.emitLoad(dst
, m_value
);
104 // ------------------------------ NumberNode -----------------------------------
106 RegisterID
* NumberNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
108 if (dst
== generator
.ignoredResult())
110 return generator
.emitLoad(dst
, m_value
);
113 // ------------------------------ StringNode -----------------------------------
115 RegisterID
* StringNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
117 if (dst
== generator
.ignoredResult())
119 return generator
.emitLoad(dst
, m_value
);
122 // ------------------------------ RegExpNode -----------------------------------
124 RegisterID
* RegExpNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
126 if (dst
== generator
.ignoredResult())
128 return generator
.emitNewRegExp(generator
.finalDestination(dst
), RegExp::create(*generator
.globalData(), m_pattern
.ustring(), regExpFlags(m_flags
.ustring())));
131 // ------------------------------ ThisNode -------------------------------------
133 RegisterID
* ThisNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
135 if (dst
== generator
.ignoredResult())
137 return generator
.moveToDestinationIfNeeded(dst
, generator
.thisRegister());
140 // ------------------------------ ResolveNode ----------------------------------
142 bool ResolveNode::isPure(BytecodeGenerator
& generator
) const
144 return generator
.isLocal(m_ident
);
147 RegisterID
* ResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
149 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
150 if (dst
== generator
.ignoredResult())
152 return generator
.moveToDestinationIfNeeded(dst
, local
);
155 generator
.emitExpressionInfo(m_startOffset
+ m_ident
.length(), m_ident
.length(), 0);
156 return generator
.emitResolve(generator
.finalDestination(dst
), m_ident
);
159 // ------------------------------ ArrayNode ------------------------------------
161 RegisterID
* ArrayNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
163 // FIXME: Should we put all of this code into emitNewArray?
166 ElementNode
* firstPutElement
;
167 for (firstPutElement
= m_element
; firstPutElement
; firstPutElement
= firstPutElement
->next()) {
168 if (firstPutElement
->elision())
173 if (!firstPutElement
&& !m_elision
)
174 return generator
.emitNewArray(generator
.finalDestination(dst
), m_element
, length
);
176 RefPtr
<RegisterID
> array
= generator
.emitNewArray(generator
.tempDestination(dst
), m_element
, length
);
178 for (ElementNode
* n
= firstPutElement
; n
; n
= n
->next()) {
179 RegisterID
* value
= generator
.emitNode(n
->value());
180 length
+= n
->elision();
181 generator
.emitPutByIndex(array
.get(), length
++, value
);
185 RegisterID
* value
= generator
.emitLoad(0, jsNumber(m_elision
+ length
));
186 generator
.emitPutById(array
.get(), generator
.propertyNames().length
, value
);
189 return generator
.moveToDestinationIfNeeded(dst
, array
.get());
192 bool ArrayNode::isSimpleArray() const
194 if (m_elision
|| m_optional
)
196 for (ElementNode
* ptr
= m_element
; ptr
; ptr
= ptr
->next()) {
203 ArgumentListNode
* ArrayNode::toArgumentList(JSGlobalData
* globalData
, int lineNumber
) const
205 ASSERT(!m_elision
&& !m_optional
);
206 ElementNode
* ptr
= m_element
;
209 ArgumentListNode
* head
= new (globalData
) ArgumentListNode(lineNumber
, ptr
->value());
210 ArgumentListNode
* tail
= head
;
212 for (; ptr
; ptr
= ptr
->next()) {
213 ASSERT(!ptr
->elision());
214 tail
= new (globalData
) ArgumentListNode(lineNumber
, tail
, ptr
->value());
219 // ------------------------------ ObjectLiteralNode ----------------------------
221 RegisterID
* ObjectLiteralNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
224 if (dst
== generator
.ignoredResult())
226 return generator
.emitNewObject(generator
.finalDestination(dst
));
228 return generator
.emitNode(dst
, m_list
);
231 // ------------------------------ PropertyListNode -----------------------------
233 RegisterID
* PropertyListNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
235 RefPtr
<RegisterID
> newObj
= generator
.tempDestination(dst
);
237 generator
.emitNewObject(newObj
.get());
239 // Fast case: this loop just handles regular value properties.
240 PropertyListNode
* p
= this;
241 for (; p
&& p
->m_node
->m_type
== PropertyNode::Constant
; p
= p
->m_next
)
242 generator
.emitDirectPutById(newObj
.get(), p
->m_node
->name(), generator
.emitNode(p
->m_node
->m_assign
));
244 // Were there any get/set properties?
246 typedef std::pair
<PropertyNode
*, PropertyNode
*> GetterSetterPair
;
247 typedef HashMap
<StringImpl
*, GetterSetterPair
> GetterSetterMap
;
250 // Build a map, pairing get/set values together.
251 for (PropertyListNode
* q
= p
; q
; q
= q
->m_next
) {
252 PropertyNode
* node
= q
->m_node
;
253 if (node
->m_type
== PropertyNode::Constant
)
256 GetterSetterPair
pair(node
, static_cast<PropertyNode
*>(0));
257 GetterSetterMap::AddResult result
= map
.add(node
->name().impl(), pair
);
258 if (!result
.isNewEntry
)
259 result
.iterator
->second
.second
= node
;
262 // Iterate over the remaining properties in the list.
263 for (; p
; p
= p
->m_next
) {
264 PropertyNode
* node
= p
->m_node
;
265 RegisterID
* value
= generator
.emitNode(node
->m_assign
);
267 // Handle regular values.
268 if (node
->m_type
== PropertyNode::Constant
) {
269 generator
.emitDirectPutById(newObj
.get(), node
->name(), value
);
273 // This is a get/set property, find its entry in the map.
274 ASSERT(node
->m_type
== PropertyNode::Getter
|| node
->m_type
== PropertyNode::Setter
);
275 GetterSetterMap::iterator it
= map
.find(node
->name().impl());
276 ASSERT(it
!= map
.end());
277 GetterSetterPair
& pair
= it
->second
;
279 // Was this already generated as a part of its partner?
280 if (pair
.second
== node
)
283 // Generate the paired node now.
284 RefPtr
<RegisterID
> getterReg
;
285 RefPtr
<RegisterID
> setterReg
;
287 if (node
->m_type
== PropertyNode::Getter
) {
290 ASSERT(pair
.second
->m_type
== PropertyNode::Setter
);
291 setterReg
= generator
.emitNode(pair
.second
->m_assign
);
293 setterReg
= generator
.newTemporary();
294 generator
.emitLoad(setterReg
.get(), jsUndefined());
297 ASSERT(node
->m_type
== PropertyNode::Setter
);
300 ASSERT(pair
.second
->m_type
== PropertyNode::Getter
);
301 getterReg
= generator
.emitNode(pair
.second
->m_assign
);
303 getterReg
= generator
.newTemporary();
304 generator
.emitLoad(getterReg
.get(), jsUndefined());
308 generator
.emitPutGetterSetter(newObj
.get(), node
->name(), getterReg
.get(), setterReg
.get());
312 return generator
.moveToDestinationIfNeeded(dst
, newObj
.get());
315 // ------------------------------ BracketAccessorNode --------------------------------
317 RegisterID
* BracketAccessorNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
319 if (m_base
->isResolveNode() && generator
.willResolveToArguments(static_cast<ResolveNode
*>(m_base
)->identifier())) {
320 RegisterID
* property
= generator
.emitNode(m_subscript
);
321 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
322 return generator
.emitGetArgumentByVal(generator
.finalDestination(dst
), generator
.uncheckedRegisterForArguments(), property
);
325 RefPtr
<RegisterID
> base
= generator
.emitNodeForLeftHandSide(m_base
, m_subscriptHasAssignments
, m_subscript
->isPure(generator
));
326 RegisterID
* property
= generator
.emitNode(m_subscript
);
327 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
328 return generator
.emitGetByVal(generator
.finalDestination(dst
), base
.get(), property
);
331 // ------------------------------ DotAccessorNode --------------------------------
333 RegisterID
* DotAccessorNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
335 if (m_ident
== generator
.propertyNames().length
) {
336 if (!m_base
->isResolveNode())
337 goto nonArgumentsPath
;
338 ResolveNode
* resolveNode
= static_cast<ResolveNode
*>(m_base
);
339 if (!generator
.willResolveToArguments(resolveNode
->identifier()))
340 goto nonArgumentsPath
;
341 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
342 return generator
.emitGetArgumentsLength(generator
.finalDestination(dst
), generator
.uncheckedRegisterForArguments());
346 RegisterID
* base
= generator
.emitNode(m_base
);
347 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
348 return generator
.emitGetById(generator
.finalDestination(dst
), base
, m_ident
);
351 // ------------------------------ ArgumentListNode -----------------------------
353 RegisterID
* ArgumentListNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
356 return generator
.emitNode(dst
, m_expr
);
359 // ------------------------------ NewExprNode ----------------------------------
361 RegisterID
* NewExprNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
363 RefPtr
<RegisterID
> func
= generator
.emitNode(m_expr
);
364 CallArguments
callArguments(generator
, m_args
);
365 return generator
.emitConstruct(generator
.finalDestinationOrIgnored(dst
), func
.get(), callArguments
, divot(), startOffset(), endOffset());
368 inline CallArguments::CallArguments(BytecodeGenerator
& generator
, ArgumentsNode
* argumentsNode
)
369 : m_argumentsNode(argumentsNode
)
371 if (generator
.shouldEmitProfileHooks())
372 m_profileHookRegister
= generator
.newTemporary();
374 size_t argumentCountIncludingThis
= 1; // 'this' register.
376 for (ArgumentListNode
* node
= argumentsNode
->m_listNode
; node
; node
= node
->m_next
)
377 ++argumentCountIncludingThis
;
380 m_argv
.grow(argumentCountIncludingThis
);
381 for (int i
= argumentCountIncludingThis
- 1; i
>= 0; --i
) {
382 m_argv
[i
] = generator
.newTemporary();
383 ASSERT(static_cast<size_t>(i
) == m_argv
.size() - 1 || m_argv
[i
]->index() == m_argv
[i
+ 1]->index() + 1);
387 inline void CallArguments::newArgument(BytecodeGenerator
& generator
)
389 RefPtr
<RegisterID
> tmp
= generator
.newTemporary();
390 ASSERT(m_argv
.isEmpty() || tmp
->index() == m_argv
.last()->index() + 1); // Calling convention assumes that all arguments are contiguous.
391 m_argv
.append(tmp
.release());
394 // ------------------------------ EvalFunctionCallNode ----------------------------------
396 RegisterID
* EvalFunctionCallNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
398 RefPtr
<RegisterID
> func
= generator
.tempDestination(dst
);
399 CallArguments
callArguments(generator
, m_args
);
400 generator
.emitExpressionInfo(divot() - startOffset() + 4, 4, 0);
401 generator
.emitResolveWithThis(callArguments
.thisRegister(), func
.get(), generator
.propertyNames().eval
);
402 return generator
.emitCallEval(generator
.finalDestination(dst
, func
.get()), func
.get(), callArguments
, divot(), startOffset(), endOffset());
405 // ------------------------------ FunctionCallValueNode ----------------------------------
407 RegisterID
* FunctionCallValueNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
409 RefPtr
<RegisterID
> func
= generator
.emitNode(m_expr
);
410 CallArguments
callArguments(generator
, m_args
);
411 generator
.emitLoad(callArguments
.thisRegister(), jsUndefined());
412 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, func
.get()), func
.get(), callArguments
, divot(), startOffset(), endOffset());
415 // ------------------------------ FunctionCallResolveNode ----------------------------------
417 RegisterID
* FunctionCallResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
419 if (RefPtr
<RegisterID
> local
= generator
.registerFor(m_ident
)) {
420 RefPtr
<RegisterID
> function
= generator
.emitMove(generator
.tempDestination(dst
), local
.get());
421 CallArguments
callArguments(generator
, m_args
);
422 generator
.emitLoad(callArguments
.thisRegister(), jsUndefined());
423 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, callArguments
.thisRegister()), function
.get(), callArguments
, divot(), startOffset(), endOffset());
428 JSObject
* globalObject
= 0;
429 bool requiresDynamicChecks
= false;
430 if (generator
.findScopedProperty(m_ident
, index
, depth
, false, requiresDynamicChecks
, globalObject
) && index
!= missingSymbolMarker() && !requiresDynamicChecks
) {
431 RefPtr
<RegisterID
> func
= generator
.emitGetScopedVar(generator
.newTemporary(), depth
, index
, globalObject
);
432 CallArguments
callArguments(generator
, m_args
);
433 generator
.emitLoad(callArguments
.thisRegister(), jsUndefined());
434 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, func
.get()), func
.get(), callArguments
, divot(), startOffset(), endOffset());
437 RefPtr
<RegisterID
> func
= generator
.newTemporary();
438 CallArguments
callArguments(generator
, m_args
);
439 int identifierStart
= divot() - startOffset();
440 generator
.emitExpressionInfo(identifierStart
+ m_ident
.length(), m_ident
.length(), 0);
441 generator
.emitResolveWithThis(callArguments
.thisRegister(), func
.get(), m_ident
);
442 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, func
.get()), func
.get(), callArguments
, divot(), startOffset(), endOffset());
445 // ------------------------------ FunctionCallBracketNode ----------------------------------
447 RegisterID
* FunctionCallBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
449 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
450 RegisterID
* property
= generator
.emitNode(m_subscript
);
451 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
452 RefPtr
<RegisterID
> function
= generator
.emitGetByVal(generator
.tempDestination(dst
), base
.get(), property
);
453 CallArguments
callArguments(generator
, m_args
);
454 generator
.emitMove(callArguments
.thisRegister(), base
.get());
455 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, function
.get()), function
.get(), callArguments
, divot(), startOffset(), endOffset());
458 // ------------------------------ FunctionCallDotNode ----------------------------------
460 RegisterID
* FunctionCallDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
462 RefPtr
<RegisterID
> function
= generator
.tempDestination(dst
);
463 CallArguments
callArguments(generator
, m_args
);
464 generator
.emitNode(callArguments
.thisRegister(), m_base
);
465 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
466 generator
.emitMethodCheck();
467 generator
.emitGetById(function
.get(), callArguments
.thisRegister(), m_ident
);
468 return generator
.emitCall(generator
.finalDestinationOrIgnored(dst
, function
.get()), function
.get(), callArguments
, divot(), startOffset(), endOffset());
471 RegisterID
* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
473 RefPtr
<Label
> realCall
= generator
.newLabel();
474 RefPtr
<Label
> end
= generator
.newLabel();
475 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
476 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
477 RefPtr
<RegisterID
> function
= generator
.emitGetById(generator
.tempDestination(dst
), base
.get(), m_ident
);
478 RefPtr
<RegisterID
> finalDestinationOrIgnored
= generator
.finalDestinationOrIgnored(dst
, function
.get());
479 generator
.emitJumpIfNotFunctionCall(function
.get(), realCall
.get());
481 if (m_args
->m_listNode
&& m_args
->m_listNode
->m_expr
) {
482 ArgumentListNode
* oldList
= m_args
->m_listNode
;
483 m_args
->m_listNode
= m_args
->m_listNode
->m_next
;
485 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
486 CallArguments
callArguments(generator
, m_args
);
487 generator
.emitNode(callArguments
.thisRegister(), oldList
->m_expr
);
488 generator
.emitCall(finalDestinationOrIgnored
.get(), realFunction
.get(), callArguments
, divot(), startOffset(), endOffset());
489 generator
.emitJump(end
.get());
491 m_args
->m_listNode
= oldList
;
493 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
494 CallArguments
callArguments(generator
, m_args
);
495 generator
.emitLoad(callArguments
.thisRegister(), jsUndefined());
496 generator
.emitCall(finalDestinationOrIgnored
.get(), realFunction
.get(), callArguments
, divot(), startOffset(), endOffset());
497 generator
.emitJump(end
.get());
500 generator
.emitLabel(realCall
.get());
502 CallArguments
callArguments(generator
, m_args
);
503 generator
.emitMove(callArguments
.thisRegister(), base
.get());
504 generator
.emitCall(finalDestinationOrIgnored
.get(), function
.get(), callArguments
, divot(), startOffset(), endOffset());
506 generator
.emitLabel(end
.get());
507 return finalDestinationOrIgnored
.get();
510 static bool areTrivialApplyArguments(ArgumentsNode
* args
)
512 return !args
->m_listNode
|| !args
->m_listNode
->m_expr
|| !args
->m_listNode
->m_next
513 || (!args
->m_listNode
->m_next
->m_next
&& args
->m_listNode
->m_next
->m_expr
->isSimpleArray());
516 RegisterID
* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
518 // A few simple cases can be trivially handled as ordinary function calls.
519 // function.apply(), function.apply(arg) -> identical to function.call
520 // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation
521 bool mayBeCall
= areTrivialApplyArguments(m_args
);
523 RefPtr
<Label
> realCall
= generator
.newLabel();
524 RefPtr
<Label
> end
= generator
.newLabel();
525 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
526 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
527 RefPtr
<RegisterID
> function
= generator
.emitGetById(generator
.tempDestination(dst
), base
.get(), m_ident
);
528 RefPtr
<RegisterID
> finalDestinationOrIgnored
= generator
.finalDestinationOrIgnored(dst
, function
.get());
529 generator
.emitJumpIfNotFunctionApply(function
.get(), realCall
.get());
532 if (m_args
->m_listNode
&& m_args
->m_listNode
->m_expr
) {
533 ArgumentListNode
* oldList
= m_args
->m_listNode
;
534 if (m_args
->m_listNode
->m_next
) {
535 ASSERT(m_args
->m_listNode
->m_next
->m_expr
->isSimpleArray());
536 ASSERT(!m_args
->m_listNode
->m_next
->m_next
);
537 m_args
->m_listNode
= static_cast<ArrayNode
*>(m_args
->m_listNode
->m_next
->m_expr
)->toArgumentList(generator
.globalData(), 0);
538 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
539 CallArguments
callArguments(generator
, m_args
);
540 generator
.emitNode(callArguments
.thisRegister(), oldList
->m_expr
);
541 generator
.emitCall(finalDestinationOrIgnored
.get(), realFunction
.get(), callArguments
, divot(), startOffset(), endOffset());
543 m_args
->m_listNode
= m_args
->m_listNode
->m_next
;
544 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
545 CallArguments
callArguments(generator
, m_args
);
546 generator
.emitNode(callArguments
.thisRegister(), oldList
->m_expr
);
547 generator
.emitCall(finalDestinationOrIgnored
.get(), realFunction
.get(), callArguments
, divot(), startOffset(), endOffset());
549 m_args
->m_listNode
= oldList
;
551 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
552 CallArguments
callArguments(generator
, m_args
);
553 generator
.emitLoad(callArguments
.thisRegister(), jsUndefined());
554 generator
.emitCall(finalDestinationOrIgnored
.get(), realFunction
.get(), callArguments
, divot(), startOffset(), endOffset());
557 ASSERT(m_args
->m_listNode
&& m_args
->m_listNode
->m_next
);
558 RefPtr
<RegisterID
> profileHookRegister
;
559 if (generator
.shouldEmitProfileHooks())
560 profileHookRegister
= generator
.newTemporary();
561 RefPtr
<RegisterID
> realFunction
= generator
.emitMove(generator
.tempDestination(dst
), base
.get());
562 RefPtr
<RegisterID
> thisRegister
= generator
.emitNode(m_args
->m_listNode
->m_expr
);
563 RefPtr
<RegisterID
> argsRegister
;
564 ArgumentListNode
* args
= m_args
->m_listNode
->m_next
;
565 if (args
->m_expr
->isResolveNode() && generator
.willResolveToArguments(static_cast<ResolveNode
*>(args
->m_expr
)->identifier()))
566 argsRegister
= generator
.uncheckedRegisterForArguments();
568 argsRegister
= generator
.emitNode(args
->m_expr
);
570 // Function.prototype.apply ignores extra arguments, but we still
571 // need to evaluate them for side effects.
572 while ((args
= args
->m_next
))
573 generator
.emitNode(args
->m_expr
);
575 generator
.emitCallVarargs(finalDestinationOrIgnored
.get(), realFunction
.get(), thisRegister
.get(), argsRegister
.get(), generator
.newTemporary(), profileHookRegister
.get(), divot(), startOffset(), endOffset());
577 generator
.emitJump(end
.get());
579 generator
.emitLabel(realCall
.get());
581 CallArguments
callArguments(generator
, m_args
);
582 generator
.emitMove(callArguments
.thisRegister(), base
.get());
583 generator
.emitCall(finalDestinationOrIgnored
.get(), function
.get(), callArguments
, divot(), startOffset(), endOffset());
585 generator
.emitLabel(end
.get());
586 return finalDestinationOrIgnored
.get();
589 // ------------------------------ PostfixResolveNode ----------------------------------
591 static RegisterID
* emitPreIncOrDec(BytecodeGenerator
& generator
, RegisterID
* srcDst
, Operator oper
)
593 return (oper
== OpPlusPlus
) ? generator
.emitPreInc(srcDst
) : generator
.emitPreDec(srcDst
);
596 static RegisterID
* emitPostIncOrDec(BytecodeGenerator
& generator
, RegisterID
* dst
, RegisterID
* srcDst
, Operator oper
)
599 return generator
.emitToJSNumber(dst
, srcDst
);
600 return (oper
== OpPlusPlus
) ? generator
.emitPostInc(dst
, srcDst
) : generator
.emitPostDec(dst
, srcDst
);
603 RegisterID
* PostfixResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
605 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
606 if (generator
.isLocalConstant(m_ident
)) {
607 if (dst
== generator
.ignoredResult())
609 return generator
.emitToJSNumber(generator
.finalDestination(dst
), local
);
612 if (dst
== generator
.ignoredResult())
613 return emitPreIncOrDec(generator
, local
, m_operator
);
614 return emitPostIncOrDec(generator
, generator
.finalDestination(dst
), local
, m_operator
);
619 JSObject
* globalObject
= 0;
620 bool requiresDynamicChecks
= false;
621 if (generator
.findScopedProperty(m_ident
, index
, depth
, true, requiresDynamicChecks
, globalObject
) && index
!= missingSymbolMarker() && !requiresDynamicChecks
) {
622 RefPtr
<RegisterID
> value
= generator
.emitGetScopedVar(generator
.newTemporary(), depth
, index
, globalObject
);
623 RegisterID
* oldValue
;
624 if (dst
== generator
.ignoredResult()) {
626 emitPreIncOrDec(generator
, value
.get(), m_operator
);
628 oldValue
= emitPostIncOrDec(generator
, generator
.finalDestination(dst
), value
.get(), m_operator
);
630 generator
.emitPutScopedVar(depth
, index
, value
.get(), globalObject
);
634 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
635 RefPtr
<RegisterID
> value
= generator
.newTemporary();
636 RefPtr
<RegisterID
> base
= generator
.emitResolveWithBase(generator
.newTemporary(), value
.get(), m_ident
);
637 RegisterID
* oldValue
;
638 if (dst
== generator
.ignoredResult()) {
640 emitPreIncOrDec(generator
, value
.get(), m_operator
);
642 oldValue
= emitPostIncOrDec(generator
, generator
.finalDestination(dst
), value
.get(), m_operator
);
644 generator
.emitPutById(base
.get(), m_ident
, value
.get());
648 // ------------------------------ PostfixBracketNode ----------------------------------
650 RegisterID
* PostfixBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
652 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
653 RefPtr
<RegisterID
> property
= generator
.emitNode(m_subscript
);
655 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
656 RefPtr
<RegisterID
> value
= generator
.emitGetByVal(generator
.newTemporary(), base
.get(), property
.get());
657 RegisterID
* oldValue
;
658 if (dst
== generator
.ignoredResult()) {
660 if (m_operator
== OpPlusPlus
)
661 generator
.emitPreInc(value
.get());
663 generator
.emitPreDec(value
.get());
665 oldValue
= (m_operator
== OpPlusPlus
) ? generator
.emitPostInc(generator
.finalDestination(dst
), value
.get()) : generator
.emitPostDec(generator
.finalDestination(dst
), value
.get());
667 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
668 generator
.emitPutByVal(base
.get(), property
.get(), value
.get());
672 // ------------------------------ PostfixDotNode ----------------------------------
674 RegisterID
* PostfixDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
676 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
678 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
679 RefPtr
<RegisterID
> value
= generator
.emitGetById(generator
.newTemporary(), base
.get(), m_ident
);
680 RegisterID
* oldValue
;
681 if (dst
== generator
.ignoredResult()) {
683 if (m_operator
== OpPlusPlus
)
684 generator
.emitPreInc(value
.get());
686 generator
.emitPreDec(value
.get());
688 oldValue
= (m_operator
== OpPlusPlus
) ? generator
.emitPostInc(generator
.finalDestination(dst
), value
.get()) : generator
.emitPostDec(generator
.finalDestination(dst
), value
.get());
690 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
691 generator
.emitPutById(base
.get(), m_ident
, value
.get());
695 // ------------------------------ PostfixErrorNode -----------------------------------
697 RegisterID
* PostfixErrorNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
699 return emitThrowReferenceError(generator
, m_operator
== OpPlusPlus
700 ? "Postfix ++ operator applied to value that is not a reference."
701 : "Postfix -- operator applied to value that is not a reference.");
704 // ------------------------------ DeleteResolveNode -----------------------------------
706 RegisterID
* DeleteResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
708 if (generator
.registerFor(m_ident
))
709 return generator
.emitLoad(generator
.finalDestination(dst
), false);
711 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
712 RegisterID
* base
= generator
.emitResolveBase(generator
.tempDestination(dst
), m_ident
);
713 return generator
.emitDeleteById(generator
.finalDestination(dst
, base
), base
, m_ident
);
716 // ------------------------------ DeleteBracketNode -----------------------------------
718 RegisterID
* DeleteBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
720 RefPtr
<RegisterID
> r0
= generator
.emitNode(m_base
);
721 RegisterID
* r1
= generator
.emitNode(m_subscript
);
723 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
724 return generator
.emitDeleteByVal(generator
.finalDestination(dst
), r0
.get(), r1
);
727 // ------------------------------ DeleteDotNode -----------------------------------
729 RegisterID
* DeleteDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
731 RegisterID
* r0
= generator
.emitNode(m_base
);
733 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
734 return generator
.emitDeleteById(generator
.finalDestination(dst
), r0
, m_ident
);
737 // ------------------------------ DeleteValueNode -----------------------------------
739 RegisterID
* DeleteValueNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
741 generator
.emitNode(generator
.ignoredResult(), m_expr
);
743 // delete on a non-location expression ignores the value and returns true
744 return generator
.emitLoad(generator
.finalDestination(dst
), true);
747 // ------------------------------ VoidNode -------------------------------------
749 RegisterID
* VoidNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
751 if (dst
== generator
.ignoredResult()) {
752 generator
.emitNode(generator
.ignoredResult(), m_expr
);
755 RefPtr
<RegisterID
> r0
= generator
.emitNode(m_expr
);
756 return generator
.emitLoad(dst
, jsUndefined());
759 // ------------------------------ TypeOfValueNode -----------------------------------
761 RegisterID
* TypeOfResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
763 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
764 if (dst
== generator
.ignoredResult())
766 return generator
.emitTypeOf(generator
.finalDestination(dst
), local
);
769 RefPtr
<RegisterID
> scratch
= generator
.emitResolveBase(generator
.tempDestination(dst
), m_ident
);
770 generator
.emitGetById(scratch
.get(), scratch
.get(), m_ident
);
771 if (dst
== generator
.ignoredResult())
773 return generator
.emitTypeOf(generator
.finalDestination(dst
, scratch
.get()), scratch
.get());
776 // ------------------------------ TypeOfValueNode -----------------------------------
778 RegisterID
* TypeOfValueNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
780 if (dst
== generator
.ignoredResult()) {
781 generator
.emitNode(generator
.ignoredResult(), m_expr
);
784 RefPtr
<RegisterID
> src
= generator
.emitNode(m_expr
);
785 return generator
.emitTypeOf(generator
.finalDestination(dst
), src
.get());
788 // ------------------------------ PrefixResolveNode ----------------------------------
790 RegisterID
* PrefixResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
792 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
793 if (generator
.isLocalConstant(m_ident
)) {
794 if (dst
== generator
.ignoredResult())
796 RefPtr
<RegisterID
> r0
= generator
.emitLoad(generator
.finalDestination(dst
), (m_operator
== OpPlusPlus
) ? 1.0 : -1.0);
797 return generator
.emitBinaryOp(op_add
, r0
.get(), local
, r0
.get(), OperandTypes());
800 emitPreIncOrDec(generator
, local
, m_operator
);
801 return generator
.moveToDestinationIfNeeded(dst
, local
);
806 JSObject
* globalObject
= 0;
807 bool requiresDynamicChecks
= false;
808 if (generator
.findScopedProperty(m_ident
, index
, depth
, true, requiresDynamicChecks
, globalObject
) && index
!= missingSymbolMarker() && !requiresDynamicChecks
) {
809 RefPtr
<RegisterID
> propDst
= generator
.emitGetScopedVar(generator
.tempDestination(dst
), depth
, index
, globalObject
);
810 emitPreIncOrDec(generator
, propDst
.get(), m_operator
);
811 generator
.emitPutScopedVar(depth
, index
, propDst
.get(), globalObject
);
812 return generator
.moveToDestinationIfNeeded(dst
, propDst
.get());
815 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
816 RefPtr
<RegisterID
> propDst
= generator
.tempDestination(dst
);
817 RefPtr
<RegisterID
> base
= generator
.emitResolveWithBase(generator
.newTemporary(), propDst
.get(), m_ident
);
818 emitPreIncOrDec(generator
, propDst
.get(), m_operator
);
819 generator
.emitPutById(base
.get(), m_ident
, propDst
.get());
820 return generator
.moveToDestinationIfNeeded(dst
, propDst
.get());
823 // ------------------------------ PrefixBracketNode ----------------------------------
825 RegisterID
* PrefixBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
827 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
828 RefPtr
<RegisterID
> property
= generator
.emitNode(m_subscript
);
829 RefPtr
<RegisterID
> propDst
= generator
.tempDestination(dst
);
831 generator
.emitExpressionInfo(divot() + m_subexpressionDivotOffset
, m_subexpressionStartOffset
, endOffset() - m_subexpressionDivotOffset
);
832 RegisterID
* value
= generator
.emitGetByVal(propDst
.get(), base
.get(), property
.get());
833 if (m_operator
== OpPlusPlus
)
834 generator
.emitPreInc(value
);
836 generator
.emitPreDec(value
);
837 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
838 generator
.emitPutByVal(base
.get(), property
.get(), value
);
839 return generator
.moveToDestinationIfNeeded(dst
, propDst
.get());
842 // ------------------------------ PrefixDotNode ----------------------------------
844 RegisterID
* PrefixDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
846 RefPtr
<RegisterID
> base
= generator
.emitNode(m_base
);
847 RefPtr
<RegisterID
> propDst
= generator
.tempDestination(dst
);
849 generator
.emitExpressionInfo(divot() + m_subexpressionDivotOffset
, m_subexpressionStartOffset
, endOffset() - m_subexpressionDivotOffset
);
850 RegisterID
* value
= generator
.emitGetById(propDst
.get(), base
.get(), m_ident
);
851 if (m_operator
== OpPlusPlus
)
852 generator
.emitPreInc(value
);
854 generator
.emitPreDec(value
);
855 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
856 generator
.emitPutById(base
.get(), m_ident
, value
);
857 return generator
.moveToDestinationIfNeeded(dst
, propDst
.get());
860 // ------------------------------ PrefixErrorNode -----------------------------------
862 RegisterID
* PrefixErrorNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
864 return emitThrowReferenceError(generator
, m_operator
== OpPlusPlus
865 ? "Prefix ++ operator applied to value that is not a reference."
866 : "Prefix -- operator applied to value that is not a reference.");
869 // ------------------------------ Unary Operation Nodes -----------------------------------
871 RegisterID
* UnaryOpNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
873 RegisterID
* src
= generator
.emitNode(m_expr
);
874 return generator
.emitUnaryOp(opcodeID(), generator
.finalDestination(dst
), src
);
877 // ------------------------------ BitwiseNotNode -----------------------------------
879 RegisterID
* BitwiseNotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
881 RefPtr
<RegisterID
> src2
= generator
.emitLoad(generator
.newTemporary(), jsNumber(-1));
882 RegisterID
* src1
= generator
.emitNode(m_expr
);
883 return generator
.emitBinaryOp(op_bitxor
, generator
.finalDestination(dst
, src1
), src1
, src2
.get(), OperandTypes(m_expr
->resultDescriptor(), ResultType::numberTypeIsInt32()));
886 // ------------------------------ LogicalNotNode -----------------------------------
888 void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator
& generator
, Label
* trueTarget
, Label
* falseTarget
, bool fallThroughMeansTrue
)
890 ASSERT(expr()->hasConditionContextCodegen());
892 // reverse the true and false targets
893 generator
.emitNodeInConditionContext(expr(), falseTarget
, trueTarget
, !fallThroughMeansTrue
);
897 // ------------------------------ Binary Operation Nodes -----------------------------------
899 // BinaryOpNode::emitStrcat:
901 // This node generates an op_strcat operation. This opcode can handle concatenation of three or
902 // more values, where we can determine a set of separate op_add operations would be operating on
905 // This function expects to be operating on a graph of AST nodes looking something like this:
915 // The assignment operation is optional, if it exists the register holding the value on the
916 // lefthand side of the assignment should be passing as the optional 'lhs' argument.
918 // The method should be called on the node at the root of the tree of regular binary add
919 // operations (marked in the diagram with a double set of parentheses). This node must
920 // be performing a string concatenation (determined by statically detecting that at least
921 // one child must be a string).
923 // Since the minimum number of values being concatenated together is expected to be 3, if
924 // a lhs to a concatenating assignment is not provided then the root add should have at
925 // least one left child that is also an add that can be determined to be operating on strings.
927 RegisterID
* BinaryOpNode::emitStrcat(BytecodeGenerator
& generator
, RegisterID
* dst
, RegisterID
* lhs
, ReadModifyResolveNode
* emitExpressionInfoForMe
)
930 ASSERT(resultDescriptor().definitelyIsString());
932 // Create a list of expressions for all the adds in the tree of nodes we can convert into
933 // a string concatenation. The rightmost node (c) is added first. The rightmost node is
934 // added first, and the leftmost child is never added, so the vector produced for the
935 // example above will be [ c, b ].
936 Vector
<ExpressionNode
*, 16> reverseExpressionList
;
937 reverseExpressionList
.append(m_expr2
);
939 // Examine the left child of the add. So long as this is a string add, add its right-child
940 // to the list, and keep processing along the left fork.
941 ExpressionNode
* leftMostAddChild
= m_expr1
;
942 while (leftMostAddChild
->isAdd() && leftMostAddChild
->resultDescriptor().definitelyIsString()) {
943 reverseExpressionList
.append(static_cast<AddNode
*>(leftMostAddChild
)->m_expr2
);
944 leftMostAddChild
= static_cast<AddNode
*>(leftMostAddChild
)->m_expr1
;
947 Vector
<RefPtr
<RegisterID
>, 16> temporaryRegisters
;
949 // If there is an assignment, allocate a temporary to hold the lhs after conversion.
950 // We could possibly avoid this (the lhs is converted last anyway, we could let the
951 // op_strcat node handle its conversion if required).
953 temporaryRegisters
.append(generator
.newTemporary());
955 // Emit code for the leftmost node ((a) in the example).
956 temporaryRegisters
.append(generator
.newTemporary());
957 RegisterID
* leftMostAddChildTempRegister
= temporaryRegisters
.last().get();
958 generator
.emitNode(leftMostAddChildTempRegister
, leftMostAddChild
);
960 // Note on ordering of conversions:
962 // We maintain the same ordering of conversions as we would see if the concatenations
963 // was performed as a sequence of adds (otherwise this optimization could change
964 // behaviour should an object have been provided a valueOf or toString method).
966 // Considering the above example, the sequnce of execution is:
967 // * evaluate operand (a)
968 // * evaluate operand (b)
969 // * convert (a) to primitive <- (this would be triggered by the first add)
970 // * convert (b) to primitive <- (ditto)
971 // * evaluate operand (c)
972 // * convert (c) to primitive <- (this would be triggered by the second add)
973 // And optionally, if there is an assignment:
974 // * convert (d) to primitive <- (this would be triggered by the assigning addition)
976 // As such we do not plant an op to convert the leftmost child now. Instead, use
977 // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion
978 // once the second node has been generated. However, if the leftmost child is an
979 // immediate we can trivially determine that no conversion will be required.
980 // If this is the case
981 if (leftMostAddChild
->isString())
982 leftMostAddChildTempRegister
= 0;
984 while (reverseExpressionList
.size()) {
985 ExpressionNode
* node
= reverseExpressionList
.last();
986 reverseExpressionList
.removeLast();
988 // Emit the code for the current node.
989 temporaryRegisters
.append(generator
.newTemporary());
990 generator
.emitNode(temporaryRegisters
.last().get(), node
);
992 // On the first iteration of this loop, when we first reach this point we have just
993 // generated the second node, which means it is time to convert the leftmost operand.
994 if (leftMostAddChildTempRegister
) {
995 generator
.emitToPrimitive(leftMostAddChildTempRegister
, leftMostAddChildTempRegister
);
996 leftMostAddChildTempRegister
= 0; // Only do this once.
998 // Plant a conversion for this node, if necessary.
999 if (!node
->isString())
1000 generator
.emitToPrimitive(temporaryRegisters
.last().get(), temporaryRegisters
.last().get());
1002 ASSERT(temporaryRegisters
.size() >= 3);
1004 // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated.
1005 // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now.
1006 if (emitExpressionInfoForMe
)
1007 generator
.emitExpressionInfo(emitExpressionInfoForMe
->divot(), emitExpressionInfoForMe
->startOffset(), emitExpressionInfoForMe
->endOffset());
1009 // If there is an assignment convert the lhs now. This will also copy lhs to
1010 // the temporary register we allocated for it.
1012 generator
.emitToPrimitive(temporaryRegisters
[0].get(), lhs
);
1014 return generator
.emitStrcat(generator
.finalDestination(dst
, temporaryRegisters
[0].get()), temporaryRegisters
[0].get(), temporaryRegisters
.size());
1017 RegisterID
* BinaryOpNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1019 OpcodeID opcodeID
= this->opcodeID();
1021 if (opcodeID
== op_add
&& m_expr1
->isAdd() && m_expr1
->resultDescriptor().definitelyIsString())
1022 return emitStrcat(generator
, dst
);
1024 if (opcodeID
== op_neq
) {
1025 if (m_expr1
->isNull() || m_expr2
->isNull()) {
1026 RefPtr
<RegisterID
> src
= generator
.tempDestination(dst
);
1027 generator
.emitNode(src
.get(), m_expr1
->isNull() ? m_expr2
: m_expr1
);
1028 return generator
.emitUnaryOp(op_neq_null
, generator
.finalDestination(dst
, src
.get()), src
.get());
1032 RefPtr
<RegisterID
> src1
= generator
.emitNodeForLeftHandSide(m_expr1
, m_rightHasAssignments
, m_expr2
->isPure(generator
));
1033 RegisterID
* src2
= generator
.emitNode(m_expr2
);
1034 return generator
.emitBinaryOp(opcodeID
, generator
.finalDestination(dst
, src1
.get()), src1
.get(), src2
, OperandTypes(m_expr1
->resultDescriptor(), m_expr2
->resultDescriptor()));
1037 RegisterID
* EqualNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1039 if (m_expr1
->isNull() || m_expr2
->isNull()) {
1040 RefPtr
<RegisterID
> src
= generator
.tempDestination(dst
);
1041 generator
.emitNode(src
.get(), m_expr1
->isNull() ? m_expr2
: m_expr1
);
1042 return generator
.emitUnaryOp(op_eq_null
, generator
.finalDestination(dst
, src
.get()), src
.get());
1045 RefPtr
<RegisterID
> src1
= generator
.emitNodeForLeftHandSide(m_expr1
, m_rightHasAssignments
, m_expr2
->isPure(generator
));
1046 RegisterID
* src2
= generator
.emitNode(m_expr2
);
1047 return generator
.emitEqualityOp(op_eq
, generator
.finalDestination(dst
, src1
.get()), src1
.get(), src2
);
1050 RegisterID
* StrictEqualNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1052 RefPtr
<RegisterID
> src1
= generator
.emitNodeForLeftHandSide(m_expr1
, m_rightHasAssignments
, m_expr2
->isPure(generator
));
1053 RegisterID
* src2
= generator
.emitNode(m_expr2
);
1054 return generator
.emitEqualityOp(op_stricteq
, generator
.finalDestination(dst
, src1
.get()), src1
.get(), src2
);
1057 RegisterID
* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1059 RefPtr
<RegisterID
> src1
= generator
.emitNodeForLeftHandSide(m_expr1
, m_rightHasAssignments
, m_expr2
->isPure(generator
));
1060 RegisterID
* src2
= generator
.emitNode(m_expr2
);
1061 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1062 return generator
.emitBinaryOp(opcodeID(), generator
.finalDestination(dst
, src1
.get()), src1
.get(), src2
, OperandTypes(m_expr1
->resultDescriptor(), m_expr2
->resultDescriptor()));
1065 RegisterID
* InstanceOfNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1067 RefPtr
<RegisterID
> src1
= generator
.emitNodeForLeftHandSide(m_expr1
, m_rightHasAssignments
, m_expr2
->isPure(generator
));
1068 RefPtr
<RegisterID
> src2
= generator
.emitNode(m_expr2
);
1070 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1071 generator
.emitCheckHasInstance(src2
.get());
1073 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1074 RegisterID
* src2Prototype
= generator
.emitGetById(generator
.newTemporary(), src2
.get(), generator
.globalData()->propertyNames
->prototype
);
1076 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1077 return generator
.emitInstanceOf(generator
.finalDestination(dst
, src1
.get()), src1
.get(), src2
.get(), src2Prototype
);
1080 // ------------------------------ LogicalOpNode ----------------------------
1082 RegisterID
* LogicalOpNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1084 RefPtr
<RegisterID
> temp
= generator
.tempDestination(dst
);
1085 RefPtr
<Label
> target
= generator
.newLabel();
1087 generator
.emitNode(temp
.get(), m_expr1
);
1088 if (m_operator
== OpLogicalAnd
)
1089 generator
.emitJumpIfFalse(temp
.get(), target
.get());
1091 generator
.emitJumpIfTrue(temp
.get(), target
.get());
1092 generator
.emitNode(temp
.get(), m_expr2
);
1093 generator
.emitLabel(target
.get());
1095 return generator
.moveToDestinationIfNeeded(dst
, temp
.get());
1098 void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator
& generator
, Label
* trueTarget
, Label
* falseTarget
, bool fallThroughMeansTrue
)
1100 if (m_expr1
->hasConditionContextCodegen()) {
1101 RefPtr
<Label
> afterExpr1
= generator
.newLabel();
1102 if (m_operator
== OpLogicalAnd
)
1103 generator
.emitNodeInConditionContext(m_expr1
, afterExpr1
.get(), falseTarget
, true);
1105 generator
.emitNodeInConditionContext(m_expr1
, trueTarget
, afterExpr1
.get(), false);
1106 generator
.emitLabel(afterExpr1
.get());
1108 RegisterID
* temp
= generator
.emitNode(m_expr1
);
1109 if (m_operator
== OpLogicalAnd
)
1110 generator
.emitJumpIfFalse(temp
, falseTarget
);
1112 generator
.emitJumpIfTrue(temp
, trueTarget
);
1115 if (m_expr2
->hasConditionContextCodegen())
1116 generator
.emitNodeInConditionContext(m_expr2
, trueTarget
, falseTarget
, fallThroughMeansTrue
);
1118 RegisterID
* temp
= generator
.emitNode(m_expr2
);
1119 if (fallThroughMeansTrue
)
1120 generator
.emitJumpIfFalse(temp
, falseTarget
);
1122 generator
.emitJumpIfTrue(temp
, trueTarget
);
1126 // ------------------------------ ConditionalNode ------------------------------
1128 RegisterID
* ConditionalNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1130 RefPtr
<RegisterID
> newDst
= generator
.finalDestination(dst
);
1131 RefPtr
<Label
> beforeElse
= generator
.newLabel();
1132 RefPtr
<Label
> afterElse
= generator
.newLabel();
1134 if (m_logical
->hasConditionContextCodegen()) {
1135 RefPtr
<Label
> beforeThen
= generator
.newLabel();
1136 generator
.emitNodeInConditionContext(m_logical
, beforeThen
.get(), beforeElse
.get(), true);
1137 generator
.emitLabel(beforeThen
.get());
1139 RegisterID
* cond
= generator
.emitNode(m_logical
);
1140 generator
.emitJumpIfFalse(cond
, beforeElse
.get());
1143 generator
.emitNode(newDst
.get(), m_expr1
);
1144 generator
.emitJump(afterElse
.get());
1146 generator
.emitLabel(beforeElse
.get());
1147 generator
.emitNode(newDst
.get(), m_expr2
);
1149 generator
.emitLabel(afterElse
.get());
1151 return newDst
.get();
1154 // ------------------------------ ReadModifyResolveNode -----------------------------------
1156 // FIXME: should this be moved to be a method on BytecodeGenerator?
1157 static ALWAYS_INLINE RegisterID
* emitReadModifyAssignment(BytecodeGenerator
& generator
, RegisterID
* dst
, RegisterID
* src1
, ExpressionNode
* m_right
, Operator oper
, OperandTypes types
, ReadModifyResolveNode
* emitExpressionInfoForMe
= 0)
1168 if (m_right
->isAdd() && m_right
->resultDescriptor().definitelyIsString())
1169 return static_cast<AddNode
*>(m_right
)->emitStrcat(generator
, dst
, src1
, emitExpressionInfoForMe
);
1176 opcodeID
= op_lshift
;
1179 opcodeID
= op_rshift
;
1182 opcodeID
= op_urshift
;
1185 opcodeID
= op_bitand
;
1188 opcodeID
= op_bitxor
;
1191 opcodeID
= op_bitor
;
1197 ASSERT_NOT_REACHED();
1201 RegisterID
* src2
= generator
.emitNode(m_right
);
1203 // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated.
1204 // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now.
1205 if (emitExpressionInfoForMe
)
1206 generator
.emitExpressionInfo(emitExpressionInfoForMe
->divot(), emitExpressionInfoForMe
->startOffset(), emitExpressionInfoForMe
->endOffset());
1208 return generator
.emitBinaryOp(opcodeID
, dst
, src1
, src2
, types
);
1211 RegisterID
* ReadModifyResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1213 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
1214 if (generator
.isLocalConstant(m_ident
))
1215 return emitReadModifyAssignment(generator
, generator
.finalDestination(dst
), local
, m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1217 if (generator
.leftHandSideNeedsCopy(m_rightHasAssignments
, m_right
->isPure(generator
))) {
1218 RefPtr
<RegisterID
> result
= generator
.newTemporary();
1219 generator
.emitMove(result
.get(), local
);
1220 emitReadModifyAssignment(generator
, result
.get(), result
.get(), m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1221 generator
.emitMove(local
, result
.get());
1222 return generator
.moveToDestinationIfNeeded(dst
, result
.get());
1225 RegisterID
* result
= emitReadModifyAssignment(generator
, local
, local
, m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1226 return generator
.moveToDestinationIfNeeded(dst
, result
);
1231 JSObject
* globalObject
= 0;
1232 bool requiresDynamicChecks
= false;
1233 if (generator
.findScopedProperty(m_ident
, index
, depth
, true, requiresDynamicChecks
, globalObject
) && index
!= missingSymbolMarker() && !requiresDynamicChecks
) {
1234 RefPtr
<RegisterID
> src1
= generator
.emitGetScopedVar(generator
.tempDestination(dst
), depth
, index
, globalObject
);
1235 RegisterID
* result
= emitReadModifyAssignment(generator
, generator
.finalDestination(dst
, src1
.get()), src1
.get(), m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1236 generator
.emitPutScopedVar(depth
, index
, result
, globalObject
);
1240 RefPtr
<RegisterID
> src1
= generator
.tempDestination(dst
);
1241 generator
.emitExpressionInfo(divot() - startOffset() + m_ident
.length(), m_ident
.length(), 0);
1242 RefPtr
<RegisterID
> base
= generator
.emitResolveWithBase(generator
.newTemporary(), src1
.get(), m_ident
);
1243 RegisterID
* result
= emitReadModifyAssignment(generator
, generator
.finalDestination(dst
, src1
.get()), src1
.get(), m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()), this);
1244 return generator
.emitPutById(base
.get(), m_ident
, result
);
1247 // ------------------------------ AssignResolveNode -----------------------------------
1249 RegisterID
* AssignResolveNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1251 if (RegisterID
* local
= generator
.registerFor(m_ident
)) {
1252 if (generator
.isLocalConstant(m_ident
))
1253 return generator
.emitNode(dst
, m_right
);
1255 RegisterID
* result
= generator
.emitNode(local
, m_right
);
1256 return generator
.moveToDestinationIfNeeded(dst
, result
);
1261 JSObject
* globalObject
= 0;
1262 bool requiresDynamicChecks
= false;
1263 if (generator
.findScopedProperty(m_ident
, index
, depth
, true, requiresDynamicChecks
, globalObject
) && index
!= missingSymbolMarker() && !requiresDynamicChecks
) {
1264 if (dst
== generator
.ignoredResult())
1266 RegisterID
* value
= generator
.emitNode(dst
, m_right
);
1267 generator
.emitPutScopedVar(depth
, index
, value
, globalObject
);
1271 RefPtr
<RegisterID
> base
= generator
.emitResolveBaseForPut(generator
.newTemporary(), m_ident
);
1272 if (dst
== generator
.ignoredResult())
1274 RegisterID
* value
= generator
.emitNode(dst
, m_right
);
1275 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1276 return generator
.emitPutById(base
.get(), m_ident
, value
);
1279 // ------------------------------ AssignDotNode -----------------------------------
1281 RegisterID
* AssignDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1283 RefPtr
<RegisterID
> base
= generator
.emitNodeForLeftHandSide(m_base
, m_rightHasAssignments
, m_right
->isPure(generator
));
1284 RefPtr
<RegisterID
> value
= generator
.destinationForAssignResult(dst
);
1285 RegisterID
* result
= generator
.emitNode(value
.get(), m_right
);
1286 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1287 RegisterID
* forwardResult
= (dst
== generator
.ignoredResult()) ? result
: generator
.moveToDestinationIfNeeded(generator
.tempDestination(result
), result
);
1288 generator
.emitPutById(base
.get(), m_ident
, forwardResult
);
1289 return generator
.moveToDestinationIfNeeded(dst
, forwardResult
);
1292 // ------------------------------ ReadModifyDotNode -----------------------------------
1294 RegisterID
* ReadModifyDotNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1296 RefPtr
<RegisterID
> base
= generator
.emitNodeForLeftHandSide(m_base
, m_rightHasAssignments
, m_right
->isPure(generator
));
1298 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
1299 RefPtr
<RegisterID
> value
= generator
.emitGetById(generator
.tempDestination(dst
), base
.get(), m_ident
);
1300 RegisterID
* updatedValue
= emitReadModifyAssignment(generator
, generator
.finalDestination(dst
, value
.get()), value
.get(), m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1302 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1303 return generator
.emitPutById(base
.get(), m_ident
, updatedValue
);
1306 // ------------------------------ AssignErrorNode -----------------------------------
1308 RegisterID
* AssignErrorNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
1310 return emitThrowReferenceError(generator
, "Left side of assignment is not a reference.");
1313 // ------------------------------ AssignBracketNode -----------------------------------
1315 RegisterID
* AssignBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1317 RefPtr
<RegisterID
> base
= generator
.emitNodeForLeftHandSide(m_base
, m_subscriptHasAssignments
|| m_rightHasAssignments
, m_subscript
->isPure(generator
) && m_right
->isPure(generator
));
1318 RefPtr
<RegisterID
> property
= generator
.emitNodeForLeftHandSide(m_subscript
, m_rightHasAssignments
, m_right
->isPure(generator
));
1319 RefPtr
<RegisterID
> value
= generator
.destinationForAssignResult(dst
);
1320 RegisterID
* result
= generator
.emitNode(value
.get(), m_right
);
1322 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1323 RegisterID
* forwardResult
= (dst
== generator
.ignoredResult()) ? result
: generator
.moveToDestinationIfNeeded(generator
.tempDestination(result
), result
);
1324 generator
.emitPutByVal(base
.get(), property
.get(), forwardResult
);
1325 return generator
.moveToDestinationIfNeeded(dst
, forwardResult
);
1328 // ------------------------------ ReadModifyBracketNode -----------------------------------
1330 RegisterID
* ReadModifyBracketNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1332 RefPtr
<RegisterID
> base
= generator
.emitNodeForLeftHandSide(m_base
, m_subscriptHasAssignments
|| m_rightHasAssignments
, m_subscript
->isPure(generator
) && m_right
->isPure(generator
));
1333 RefPtr
<RegisterID
> property
= generator
.emitNodeForLeftHandSide(m_subscript
, m_rightHasAssignments
, m_right
->isPure(generator
));
1335 generator
.emitExpressionInfo(divot() - m_subexpressionDivotOffset
, startOffset() - m_subexpressionDivotOffset
, m_subexpressionEndOffset
);
1336 RefPtr
<RegisterID
> value
= generator
.emitGetByVal(generator
.tempDestination(dst
), base
.get(), property
.get());
1337 RegisterID
* updatedValue
= emitReadModifyAssignment(generator
, generator
.finalDestination(dst
, value
.get()), value
.get(), m_right
, m_operator
, OperandTypes(ResultType::unknownType(), m_right
->resultDescriptor()));
1339 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1340 generator
.emitPutByVal(base
.get(), property
.get(), updatedValue
);
1342 return updatedValue
;
1345 // ------------------------------ CommaNode ------------------------------------
1347 RegisterID
* CommaNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1349 ASSERT(m_expressions
.size() > 1);
1350 for (size_t i
= 0; i
< m_expressions
.size() - 1; i
++)
1351 generator
.emitNode(generator
.ignoredResult(), m_expressions
[i
]);
1352 return generator
.emitNode(dst
, m_expressions
.last());
1355 // ------------------------------ ConstDeclNode ------------------------------------
1357 RegisterID
* ConstDeclNode::emitCodeSingle(BytecodeGenerator
& generator
)
1359 // FIXME: This code does not match the behavior of const in Firefox.
1360 if (RegisterID
* local
= generator
.constRegisterFor(m_ident
)) {
1364 return generator
.emitNode(local
, m_init
);
1367 RefPtr
<RegisterID
> value
= m_init
? generator
.emitNode(m_init
) : generator
.emitLoad(0, jsUndefined());
1369 ScopeChainIterator iter
= generator
.scopeChain()->begin();
1370 ScopeChainIterator end
= generator
.scopeChain()->end();
1372 for (; iter
!= end
; ++iter
, ++depth
) {
1373 JSObject
* currentScope
= iter
->get();
1374 if (!currentScope
->isVariableObject())
1376 JSVariableObject
* currentVariableObject
= static_cast<JSVariableObject
*>(currentScope
);
1377 SymbolTableEntry entry
= currentVariableObject
->symbolTable().get(m_ident
.impl());
1381 return generator
.emitPutScopedVar(generator
.scopeDepth() + depth
, entry
.getIndex(), value
.get(), currentVariableObject
->isGlobalObject() ? currentVariableObject
: 0);
1384 if (generator
.codeType() != EvalCode
)
1387 // FIXME: While this code should only be hit in an eval block, it will assign
1388 // to the wrong base if m_ident exists in an intervening with scope.
1389 RefPtr
<RegisterID
> base
= generator
.emitResolveBase(generator
.newTemporary(), m_ident
);
1390 return generator
.emitPutById(base
.get(), m_ident
, value
.get());
1393 RegisterID
* ConstDeclNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
1395 RegisterID
* result
= 0;
1396 for (ConstDeclNode
* n
= this; n
; n
= n
->m_next
)
1397 result
= n
->emitCodeSingle(generator
);
1402 // ------------------------------ ConstStatementNode -----------------------------
1404 RegisterID
* ConstStatementNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
1406 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1407 return generator
.emitNode(m_next
);
1410 // ------------------------------ SourceElements -------------------------------
1413 inline StatementNode
* SourceElements::lastStatement() const
1415 size_t size
= m_statements
.size();
1416 return size
? m_statements
[size
- 1] : 0;
1419 inline void SourceElements::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1421 size_t size
= m_statements
.size();
1422 for (size_t i
= 0; i
< size
; ++i
)
1423 generator
.emitNode(dst
, m_statements
[i
]);
1426 // ------------------------------ BlockNode ------------------------------------
1428 inline StatementNode
* BlockNode::lastStatement() const
1430 return m_statements
? m_statements
->lastStatement() : 0;
1433 inline StatementNode
* BlockNode::singleStatement() const
1435 return m_statements
? m_statements
->singleStatement() : 0;
1438 RegisterID
* BlockNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1441 m_statements
->emitBytecode(generator
, dst
);
1445 // ------------------------------ EmptyStatementNode ---------------------------
1447 RegisterID
* EmptyStatementNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1449 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1453 // ------------------------------ DebuggerStatementNode ---------------------------
1455 RegisterID
* DebuggerStatementNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1457 generator
.emitDebugHook(DidReachBreakpoint
, firstLine(), lastLine());
1461 // ------------------------------ ExprStatementNode ----------------------------
1463 RegisterID
* ExprStatementNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1466 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1467 return generator
.emitNode(dst
, m_expr
);
1470 // ------------------------------ VarStatementNode ----------------------------
1472 RegisterID
* VarStatementNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
1475 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1476 return generator
.emitNode(m_expr
);
1479 // ------------------------------ IfNode ---------------------------------------
1481 RegisterID
* IfNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1483 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1485 RefPtr
<Label
> afterThen
= generator
.newLabel();
1487 if (m_condition
->hasConditionContextCodegen()) {
1488 RefPtr
<Label
> beforeThen
= generator
.newLabel();
1489 generator
.emitNodeInConditionContext(m_condition
, beforeThen
.get(), afterThen
.get(), true);
1490 generator
.emitLabel(beforeThen
.get());
1492 RegisterID
* cond
= generator
.emitNode(m_condition
);
1493 generator
.emitJumpIfFalse(cond
, afterThen
.get());
1496 generator
.emitNode(dst
, m_ifBlock
);
1497 generator
.emitLabel(afterThen
.get());
1499 // FIXME: This should return the last statement executed so that it can be returned as a Completion.
1503 // ------------------------------ IfElseNode ---------------------------------------
1505 RegisterID
* IfElseNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1507 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1509 RefPtr
<Label
> beforeElse
= generator
.newLabel();
1510 RefPtr
<Label
> afterElse
= generator
.newLabel();
1512 if (m_condition
->hasConditionContextCodegen()) {
1513 RefPtr
<Label
> beforeThen
= generator
.newLabel();
1514 generator
.emitNodeInConditionContext(m_condition
, beforeThen
.get(), beforeElse
.get(), true);
1515 generator
.emitLabel(beforeThen
.get());
1517 RegisterID
* cond
= generator
.emitNode(m_condition
);
1518 generator
.emitJumpIfFalse(cond
, beforeElse
.get());
1521 generator
.emitNode(dst
, m_ifBlock
);
1522 generator
.emitJump(afterElse
.get());
1524 generator
.emitLabel(beforeElse
.get());
1526 generator
.emitNode(dst
, m_elseBlock
);
1528 generator
.emitLabel(afterElse
.get());
1530 // FIXME: This should return the last statement executed so that it can be returned as a Completion.
1534 // ------------------------------ DoWhileNode ----------------------------------
1536 RegisterID
* DoWhileNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1538 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::Loop
);
1540 RefPtr
<Label
> topOfLoop
= generator
.newLabel();
1541 generator
.emitLabel(topOfLoop
.get());
1542 generator
.emitLoopHint();
1543 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1545 RefPtr
<RegisterID
> result
= generator
.emitNode(dst
, m_statement
);
1547 generator
.emitLabel(scope
->continueTarget());
1548 generator
.emitDebugHook(WillExecuteStatement
, m_expr
->lineNo(), m_expr
->lineNo());
1549 if (m_expr
->hasConditionContextCodegen())
1550 generator
.emitNodeInConditionContext(m_expr
, topOfLoop
.get(), scope
->breakTarget(), false);
1552 RegisterID
* cond
= generator
.emitNode(m_expr
);
1553 generator
.emitJumpIfTrue(cond
, topOfLoop
.get());
1556 generator
.emitLabel(scope
->breakTarget());
1557 return result
.get();
1560 // ------------------------------ WhileNode ------------------------------------
1562 RegisterID
* WhileNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1564 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::Loop
);
1566 generator
.emitJump(scope
->continueTarget());
1568 RefPtr
<Label
> topOfLoop
= generator
.newLabel();
1569 generator
.emitLabel(topOfLoop
.get());
1570 generator
.emitLoopHint();
1572 generator
.emitNode(dst
, m_statement
);
1574 generator
.emitLabel(scope
->continueTarget());
1575 generator
.emitDebugHook(WillExecuteStatement
, m_expr
->lineNo(), m_expr
->lineNo());
1577 if (m_expr
->hasConditionContextCodegen())
1578 generator
.emitNodeInConditionContext(m_expr
, topOfLoop
.get(), scope
->breakTarget(), false);
1580 RegisterID
* cond
= generator
.emitNode(m_expr
);
1581 generator
.emitJumpIfTrue(cond
, topOfLoop
.get());
1584 generator
.emitLabel(scope
->breakTarget());
1586 // FIXME: This should return the last statement executed so that it can be returned as a Completion
1590 // ------------------------------ ForNode --------------------------------------
1592 RegisterID
* ForNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1594 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::Loop
);
1596 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1599 generator
.emitNode(generator
.ignoredResult(), m_expr1
);
1601 RefPtr
<Label
> condition
= generator
.newLabel();
1602 generator
.emitJump(condition
.get());
1604 RefPtr
<Label
> topOfLoop
= generator
.newLabel();
1605 generator
.emitLabel(topOfLoop
.get());
1606 generator
.emitLoopHint();
1608 RefPtr
<RegisterID
> result
= generator
.emitNode(dst
, m_statement
);
1610 generator
.emitLabel(scope
->continueTarget());
1611 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1613 generator
.emitNode(generator
.ignoredResult(), m_expr3
);
1615 generator
.emitLabel(condition
.get());
1617 if (m_expr2
->hasConditionContextCodegen())
1618 generator
.emitNodeInConditionContext(m_expr2
, topOfLoop
.get(), scope
->breakTarget(), false);
1620 RegisterID
* cond
= generator
.emitNode(m_expr2
);
1621 generator
.emitJumpIfTrue(cond
, topOfLoop
.get());
1624 generator
.emitJump(topOfLoop
.get());
1626 generator
.emitLabel(scope
->breakTarget());
1627 return result
.get();
1630 // ------------------------------ ForInNode ------------------------------------
1632 RegisterID
* ForInNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1634 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::Loop
);
1636 if (!m_lexpr
->isLocation())
1637 return emitThrowReferenceError(generator
, "Left side of for-in statement is not a reference.");
1639 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1642 generator
.emitNode(generator
.ignoredResult(), m_init
);
1644 RefPtr
<RegisterID
> base
= generator
.newTemporary();
1645 generator
.emitNode(base
.get(), m_expr
);
1646 RefPtr
<RegisterID
> i
= generator
.newTemporary();
1647 RefPtr
<RegisterID
> size
= generator
.newTemporary();
1648 RefPtr
<RegisterID
> expectedSubscript
;
1649 RefPtr
<RegisterID
> iter
= generator
.emitGetPropertyNames(generator
.newTemporary(), base
.get(), i
.get(), size
.get(), scope
->breakTarget());
1650 generator
.emitJump(scope
->continueTarget());
1652 RefPtr
<Label
> loopStart
= generator
.newLabel();
1653 generator
.emitLabel(loopStart
.get());
1654 generator
.emitLoopHint();
1656 RegisterID
* propertyName
;
1657 bool optimizedForinAccess
= false;
1658 if (m_lexpr
->isResolveNode()) {
1659 const Identifier
& ident
= static_cast<ResolveNode
*>(m_lexpr
)->identifier();
1660 propertyName
= generator
.registerFor(ident
);
1661 if (!propertyName
) {
1662 propertyName
= generator
.newTemporary();
1663 RefPtr
<RegisterID
> protect
= propertyName
;
1664 RegisterID
* base
= generator
.emitResolveBaseForPut(generator
.newTemporary(), ident
);
1666 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1667 generator
.emitPutById(base
, ident
, propertyName
);
1669 expectedSubscript
= generator
.emitMove(generator
.newTemporary(), propertyName
);
1670 generator
.pushOptimisedForIn(expectedSubscript
.get(), iter
.get(), i
.get(), propertyName
);
1671 optimizedForinAccess
= true;
1673 } else if (m_lexpr
->isDotAccessorNode()) {
1674 DotAccessorNode
* assignNode
= static_cast<DotAccessorNode
*>(m_lexpr
);
1675 const Identifier
& ident
= assignNode
->identifier();
1676 propertyName
= generator
.newTemporary();
1677 RefPtr
<RegisterID
> protect
= propertyName
;
1678 RegisterID
* base
= generator
.emitNode(assignNode
->base());
1680 generator
.emitExpressionInfo(assignNode
->divot(), assignNode
->startOffset(), assignNode
->endOffset());
1681 generator
.emitPutById(base
, ident
, propertyName
);
1683 ASSERT(m_lexpr
->isBracketAccessorNode());
1684 BracketAccessorNode
* assignNode
= static_cast<BracketAccessorNode
*>(m_lexpr
);
1685 propertyName
= generator
.newTemporary();
1686 RefPtr
<RegisterID
> protect
= propertyName
;
1687 RefPtr
<RegisterID
> base
= generator
.emitNode(assignNode
->base());
1688 RegisterID
* subscript
= generator
.emitNode(assignNode
->subscript());
1690 generator
.emitExpressionInfo(assignNode
->divot(), assignNode
->startOffset(), assignNode
->endOffset());
1691 generator
.emitPutByVal(base
.get(), subscript
, propertyName
);
1694 generator
.emitNode(dst
, m_statement
);
1696 if (optimizedForinAccess
)
1697 generator
.popOptimisedForIn();
1699 generator
.emitLabel(scope
->continueTarget());
1700 generator
.emitNextPropertyName(propertyName
, base
.get(), i
.get(), size
.get(), iter
.get(), loopStart
.get());
1701 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1702 generator
.emitLabel(scope
->breakTarget());
1706 // ------------------------------ ContinueNode ---------------------------------
1709 RegisterID
* ContinueNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1711 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1713 LabelScope
* scope
= generator
.continueTarget(m_ident
);
1716 generator
.emitJumpScopes(scope
->continueTarget(), scope
->scopeDepth());
1720 // ------------------------------ BreakNode ------------------------------------
1723 RegisterID
* BreakNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1725 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1727 LabelScope
* scope
= generator
.breakTarget(m_ident
);
1730 generator
.emitJumpScopes(scope
->breakTarget(), scope
->scopeDepth());
1734 // ------------------------------ ReturnNode -----------------------------------
1736 RegisterID
* ReturnNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1738 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1739 ASSERT(generator
.codeType() == FunctionCode
);
1741 if (dst
== generator
.ignoredResult())
1743 RegisterID
* r0
= m_value
? generator
.emitNode(dst
, m_value
) : generator
.emitLoad(dst
, jsUndefined());
1744 RefPtr
<RegisterID
> returnRegister
;
1745 if (generator
.scopeDepth()) {
1746 RefPtr
<Label
> l0
= generator
.newLabel();
1747 if (generator
.hasFinaliser()) {
1748 returnRegister
= generator
.emitMove(generator
.newTemporary(), r0
);
1749 r0
= returnRegister
.get();
1751 generator
.emitJumpScopes(l0
.get(), 0);
1752 generator
.emitLabel(l0
.get());
1754 generator
.emitDebugHook(WillLeaveCallFrame
, firstLine(), lastLine());
1755 return generator
.emitReturn(r0
);
1758 // ------------------------------ WithNode -------------------------------------
1760 RegisterID
* WithNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1762 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1764 RefPtr
<RegisterID
> scope
= generator
.newTemporary();
1765 generator
.emitNode(scope
.get(), m_expr
); // scope must be protected until popped
1766 generator
.emitExpressionInfo(m_divot
, m_expressionLength
, 0);
1767 generator
.emitPushScope(scope
.get());
1768 RegisterID
* result
= generator
.emitNode(dst
, m_statement
);
1769 generator
.emitPopScope();
1773 // ------------------------------ CaseClauseNode --------------------------------
1775 inline void CaseClauseNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1778 m_statements
->emitBytecode(generator
, dst
);
1781 // ------------------------------ CaseBlockNode --------------------------------
1790 static void processClauseList(ClauseListNode
* list
, Vector
<ExpressionNode
*, 8>& literalVector
, SwitchKind
& typeForTable
, bool& singleCharacterSwitch
, int32_t& min_num
, int32_t& max_num
)
1792 for (; list
; list
= list
->getNext()) {
1793 ExpressionNode
* clauseExpression
= list
->getClause()->expr();
1794 literalVector
.append(clauseExpression
);
1795 if (clauseExpression
->isNumber()) {
1796 double value
= static_cast<NumberNode
*>(clauseExpression
)->value();
1797 int32_t intVal
= static_cast<int32_t>(value
);
1798 if ((typeForTable
& ~SwitchNumber
) || (intVal
!= value
)) {
1799 typeForTable
= SwitchNeither
;
1802 if (intVal
< min_num
)
1804 if (intVal
> max_num
)
1806 typeForTable
= SwitchNumber
;
1809 if (clauseExpression
->isString()) {
1810 if (typeForTable
& ~SwitchString
) {
1811 typeForTable
= SwitchNeither
;
1814 const UString
& value
= static_cast<StringNode
*>(clauseExpression
)->value().ustring();
1815 if (singleCharacterSwitch
&= value
.length() == 1) {
1816 int32_t intVal
= value
[0];
1817 if (intVal
< min_num
)
1819 if (intVal
> max_num
)
1822 typeForTable
= SwitchString
;
1825 typeForTable
= SwitchNeither
;
1830 SwitchInfo::SwitchType
CaseBlockNode::tryOptimizedSwitch(Vector
<ExpressionNode
*, 8>& literalVector
, int32_t& min_num
, int32_t& max_num
)
1832 SwitchKind typeForTable
= SwitchUnset
;
1833 bool singleCharacterSwitch
= true;
1835 processClauseList(m_list1
, literalVector
, typeForTable
, singleCharacterSwitch
, min_num
, max_num
);
1836 processClauseList(m_list2
, literalVector
, typeForTable
, singleCharacterSwitch
, min_num
, max_num
);
1838 if (typeForTable
== SwitchUnset
|| typeForTable
== SwitchNeither
)
1839 return SwitchInfo::SwitchNone
;
1841 if (typeForTable
== SwitchNumber
) {
1842 int32_t range
= max_num
- min_num
;
1843 if (min_num
<= max_num
&& range
<= 1000 && (range
/ literalVector
.size()) < 10)
1844 return SwitchInfo::SwitchImmediate
;
1845 return SwitchInfo::SwitchNone
;
1848 ASSERT(typeForTable
== SwitchString
);
1850 if (singleCharacterSwitch
) {
1851 int32_t range
= max_num
- min_num
;
1852 if (min_num
<= max_num
&& range
<= 1000 && (range
/ literalVector
.size()) < 10)
1853 return SwitchInfo::SwitchCharacter
;
1856 return SwitchInfo::SwitchString
;
1859 RegisterID
* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator
& generator
, RegisterID
* switchExpression
, RegisterID
* dst
)
1861 RefPtr
<Label
> defaultLabel
;
1862 Vector
<RefPtr
<Label
>, 8> labelVector
;
1863 Vector
<ExpressionNode
*, 8> literalVector
;
1864 int32_t min_num
= std::numeric_limits
<int32_t>::max();
1865 int32_t max_num
= std::numeric_limits
<int32_t>::min();
1866 SwitchInfo::SwitchType switchType
= tryOptimizedSwitch(literalVector
, min_num
, max_num
);
1868 if (switchType
!= SwitchInfo::SwitchNone
) {
1869 // Prepare the various labels
1870 for (uint32_t i
= 0; i
< literalVector
.size(); i
++)
1871 labelVector
.append(generator
.newLabel());
1872 defaultLabel
= generator
.newLabel();
1873 generator
.beginSwitch(switchExpression
, switchType
);
1876 for (ClauseListNode
* list
= m_list1
; list
; list
= list
->getNext()) {
1877 RefPtr
<RegisterID
> clauseVal
= generator
.newTemporary();
1878 generator
.emitNode(clauseVal
.get(), list
->getClause()->expr());
1879 generator
.emitBinaryOp(op_stricteq
, clauseVal
.get(), clauseVal
.get(), switchExpression
, OperandTypes());
1880 labelVector
.append(generator
.newLabel());
1881 generator
.emitJumpIfTrue(clauseVal
.get(), labelVector
[labelVector
.size() - 1].get());
1884 for (ClauseListNode
* list
= m_list2
; list
; list
= list
->getNext()) {
1885 RefPtr
<RegisterID
> clauseVal
= generator
.newTemporary();
1886 generator
.emitNode(clauseVal
.get(), list
->getClause()->expr());
1887 generator
.emitBinaryOp(op_stricteq
, clauseVal
.get(), clauseVal
.get(), switchExpression
, OperandTypes());
1888 labelVector
.append(generator
.newLabel());
1889 generator
.emitJumpIfTrue(clauseVal
.get(), labelVector
[labelVector
.size() - 1].get());
1891 defaultLabel
= generator
.newLabel();
1892 generator
.emitJump(defaultLabel
.get());
1895 RegisterID
* result
= 0;
1898 for (ClauseListNode
* list
= m_list1
; list
; list
= list
->getNext()) {
1899 generator
.emitLabel(labelVector
[i
++].get());
1900 list
->getClause()->emitBytecode(generator
, dst
);
1903 if (m_defaultClause
) {
1904 generator
.emitLabel(defaultLabel
.get());
1905 m_defaultClause
->emitBytecode(generator
, dst
);
1908 for (ClauseListNode
* list
= m_list2
; list
; list
= list
->getNext()) {
1909 generator
.emitLabel(labelVector
[i
++].get());
1910 list
->getClause()->emitBytecode(generator
, dst
);
1912 if (!m_defaultClause
)
1913 generator
.emitLabel(defaultLabel
.get());
1915 ASSERT(i
== labelVector
.size());
1916 if (switchType
!= SwitchInfo::SwitchNone
) {
1917 ASSERT(labelVector
.size() == literalVector
.size());
1918 generator
.endSwitch(labelVector
.size(), labelVector
.data(), literalVector
.data(), defaultLabel
.get(), min_num
, max_num
);
1923 // ------------------------------ SwitchNode -----------------------------------
1925 RegisterID
* SwitchNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1927 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1929 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::Switch
);
1931 RefPtr
<RegisterID
> r0
= generator
.emitNode(m_expr
);
1932 RegisterID
* r1
= m_block
->emitBytecodeForBlock(generator
, r0
.get(), dst
);
1934 generator
.emitLabel(scope
->breakTarget());
1938 // ------------------------------ LabelNode ------------------------------------
1940 RegisterID
* LabelNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1942 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1944 ASSERT(!generator
.breakTarget(m_name
));
1946 RefPtr
<LabelScope
> scope
= generator
.newLabelScope(LabelScope::NamedLabel
, &m_name
);
1947 RegisterID
* r0
= generator
.emitNode(dst
, m_statement
);
1949 generator
.emitLabel(scope
->breakTarget());
1953 // ------------------------------ ThrowNode ------------------------------------
1955 RegisterID
* ThrowNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1957 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1959 if (dst
== generator
.ignoredResult())
1961 RefPtr
<RegisterID
> expr
= generator
.emitNode(m_expr
);
1962 generator
.emitExpressionInfo(divot(), startOffset(), endOffset());
1963 generator
.emitThrow(expr
.get());
1967 // ------------------------------ TryNode --------------------------------------
1969 RegisterID
* TryNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
1971 // NOTE: The catch and finally blocks must be labeled explicitly, so the
1972 // optimizer knows they may be jumped to from anywhere.
1974 generator
.emitDebugHook(WillExecuteStatement
, firstLine(), lastLine());
1976 RefPtr
<Label
> tryStartLabel
= generator
.newLabel();
1978 generator
.pushFinallyContext(m_finallyBlock
);
1980 generator
.emitLabel(tryStartLabel
.get());
1981 generator
.emitNode(dst
, m_tryBlock
);
1984 RefPtr
<Label
> catchEndLabel
= generator
.newLabel();
1986 // Normal path: jump over the catch block.
1987 generator
.emitJump(catchEndLabel
.get());
1989 // Uncaught exception path: the catch block.
1990 RefPtr
<Label
> here
= generator
.emitLabel(generator
.newLabel().get());
1991 RefPtr
<RegisterID
> exceptionRegister
= generator
.emitCatch(generator
.newTemporary(), tryStartLabel
.get(), here
.get());
1992 generator
.emitPushNewScope(exceptionRegister
.get(), m_exceptionIdent
, exceptionRegister
.get());
1993 generator
.emitNode(dst
, m_catchBlock
);
1994 generator
.emitPopScope();
1995 generator
.emitLabel(catchEndLabel
.get());
1998 if (m_finallyBlock
) {
1999 generator
.popFinallyContext();
2001 RefPtr
<Label
> finallyEndLabel
= generator
.newLabel();
2003 // Normal path: run the finally code, and jump to the end.
2004 generator
.emitNode(dst
, m_finallyBlock
);
2005 generator
.emitJump(finallyEndLabel
.get());
2007 // Uncaught exception path: invoke the finally block, then re-throw the exception.
2008 RefPtr
<Label
> here
= generator
.emitLabel(generator
.newLabel().get());
2009 RefPtr
<RegisterID
> tempExceptionRegister
= generator
.emitCatch(generator
.newTemporary(), tryStartLabel
.get(), here
.get());
2010 generator
.emitNode(dst
, m_finallyBlock
);
2011 generator
.emitThrow(tempExceptionRegister
.get());
2013 generator
.emitLabel(finallyEndLabel
.get());
2019 // ------------------------------ ScopeNode -----------------------------
2021 inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
2024 m_statements
->emitBytecode(generator
, dst
);
2027 // ------------------------------ ProgramNode -----------------------------
2029 RegisterID
* ProgramNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
2031 generator
.emitDebugHook(WillExecuteProgram
, firstLine(), lastLine());
2033 RefPtr
<RegisterID
> dstRegister
= generator
.newTemporary();
2034 generator
.emitLoad(dstRegister
.get(), jsUndefined());
2035 emitStatementsBytecode(generator
, dstRegister
.get());
2037 generator
.emitDebugHook(DidExecuteProgram
, firstLine(), lastLine());
2038 generator
.emitEnd(dstRegister
.get());
2042 // ------------------------------ EvalNode -----------------------------
2044 RegisterID
* EvalNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
2046 generator
.emitDebugHook(WillExecuteProgram
, firstLine(), lastLine());
2048 RefPtr
<RegisterID
> dstRegister
= generator
.newTemporary();
2049 generator
.emitLoad(dstRegister
.get(), jsUndefined());
2050 emitStatementsBytecode(generator
, dstRegister
.get());
2052 generator
.emitDebugHook(DidExecuteProgram
, firstLine(), lastLine());
2053 generator
.emitEnd(dstRegister
.get());
2057 // ------------------------------ FunctionBodyNode -----------------------------
2059 RegisterID
* FunctionBodyNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
*)
2061 generator
.emitDebugHook(DidEnterCallFrame
, firstLine(), lastLine());
2062 emitStatementsBytecode(generator
, generator
.ignoredResult());
2064 StatementNode
* singleStatement
= this->singleStatement();
2065 ReturnNode
* returnNode
= 0;
2067 // Check for a return statement at the end of a function composed of a single block.
2068 if (singleStatement
&& singleStatement
->isBlock()) {
2069 StatementNode
* lastStatementInBlock
= static_cast<BlockNode
*>(singleStatement
)->lastStatement();
2070 if (lastStatementInBlock
&& lastStatementInBlock
->isReturnNode())
2071 returnNode
= static_cast<ReturnNode
*>(lastStatementInBlock
);
2074 // If there is no return we must automatically insert one.
2076 RegisterID
* r0
= generator
.isConstructor() ? generator
.thisRegister() : generator
.emitLoad(0, jsUndefined());
2077 generator
.emitDebugHook(WillLeaveCallFrame
, firstLine(), lastLine());
2078 generator
.emitReturn(r0
);
2082 // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare.
2083 if (static_cast<BlockNode
*>(singleStatement
)->singleStatement()) {
2084 ExpressionNode
* returnValueExpression
= returnNode
->value();
2085 if (returnValueExpression
&& returnValueExpression
->isSubtract()) {
2086 ExpressionNode
* lhsExpression
= static_cast<SubNode
*>(returnValueExpression
)->lhs();
2087 ExpressionNode
* rhsExpression
= static_cast<SubNode
*>(returnValueExpression
)->rhs();
2088 if (lhsExpression
->isResolveNode()
2089 && rhsExpression
->isResolveNode()
2090 && generator
.isArgumentNumber(static_cast<ResolveNode
*>(lhsExpression
)->identifier(), 0)
2091 && generator
.isArgumentNumber(static_cast<ResolveNode
*>(rhsExpression
)->identifier(), 1)) {
2093 generator
.setIsNumericCompareFunction(true);
2101 // ------------------------------ FuncDeclNode ---------------------------------
2103 RegisterID
* FuncDeclNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
2105 if (dst
== generator
.ignoredResult())
2110 // ------------------------------ FuncExprNode ---------------------------------
2112 RegisterID
* FuncExprNode::emitBytecode(BytecodeGenerator
& generator
, RegisterID
* dst
)
2114 return generator
.emitNewFunctionExpression(generator
.finalDestination(dst
), this);