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