]>
Commit | Line | Data |
---|---|---|
f9bf01c6 A |
1 | /* |
2 | * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
93a37866 | 4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. |
f9bf01c6 A |
5 | * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) |
6 | * Copyright (C) 2007 Maks Orlovich | |
7 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | |
93a37866 | 8 | * Copyright (C) 2012 Igalia, S.L. |
f9bf01c6 A |
9 | * |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Library General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Library General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Library General Public License | |
21 | * along with this library; see the file COPYING.LIB. If not, write to | |
22 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
23 | * Boston, MA 02110-1301, USA. | |
24 | * | |
25 | */ | |
26 | ||
27 | #include "config.h" | |
28 | #include "Nodes.h" | |
29 | #include "NodeConstructors.h" | |
30 | ||
81345200 | 31 | #include "BuiltinNames.h" |
f9bf01c6 A |
32 | #include "BytecodeGenerator.h" |
33 | #include "CallFrame.h" | |
34 | #include "Debugger.h" | |
35 | #include "JIT.h" | |
36 | #include "JSFunction.h" | |
37 | #include "JSGlobalObject.h" | |
93a37866 | 38 | #include "JSNameScope.h" |
81345200 | 39 | #include "JSONObject.h" |
f9bf01c6 A |
40 | #include "LabelScope.h" |
41 | #include "Lexer.h" | |
81345200 | 42 | #include "JSCInlines.h" |
f9bf01c6 A |
43 | #include "Parser.h" |
44 | #include "PropertyNameArray.h" | |
4e4e5a6f | 45 | #include "RegExpCache.h" |
f9bf01c6 A |
46 | #include "RegExpObject.h" |
47 | #include "SamplingTool.h" | |
81345200 | 48 | #include "StackAlignment.h" |
f9bf01c6 A |
49 | #include <wtf/Assertions.h> |
50 | #include <wtf/RefCountedLeakCounter.h> | |
51 | #include <wtf/Threading.h> | |
52 | ||
53 | using namespace WTF; | |
54 | ||
55 | namespace JSC { | |
56 | ||
57 | /* | |
58 | Details of the emitBytecode function. | |
59 | ||
60 | Return value: The register holding the production's value. | |
61 | dst: An optional parameter specifying the most efficient destination at | |
62 | which to store the production's value. The callee must honor dst. | |
63 | ||
64 | The dst argument provides for a crude form of copy propagation. For example, | |
65 | ||
66 | x = 1 | |
67 | ||
68 | becomes | |
69 | ||
70 | load r[x], 1 | |
71 | ||
72 | instead of | |
73 | ||
74 | load r0, 1 | |
75 | mov r[x], r0 | |
76 | ||
77 | because the assignment node, "x =", passes r[x] as dst to the number node, "1". | |
78 | */ | |
79 | ||
93a37866 A |
80 | void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
81 | { | |
82 | RegisterID* result = generator.emitNode(this); | |
83 | if (fallThroughMode == FallThroughMeansTrue) | |
84 | generator.emitJumpIfFalse(result, falseTarget); | |
85 | else | |
86 | generator.emitJumpIfTrue(result, trueTarget); | |
87 | } | |
88 | ||
f9bf01c6 A |
89 | // ------------------------------ ThrowableExpressionData -------------------------------- |
90 | ||
93a37866 | 91 | RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) |
f9bf01c6 | 92 | { |
81345200 | 93 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
14957cd0 A |
94 | generator.emitThrowReferenceError(message); |
95 | return generator.newTemporary(); | |
f9bf01c6 A |
96 | } |
97 | ||
93a37866 | 98 | // ------------------------------ ConstantNode ---------------------------------- |
f9bf01c6 | 99 | |
93a37866 | 100 | void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 101 | { |
93a37866 A |
102 | TriState value = jsValue(generator).pureToBoolean(); |
103 | if (value == MixedTriState) | |
104 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); | |
105 | else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) | |
106 | generator.emitJump(trueTarget); | |
107 | else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue) | |
108 | generator.emitJump(falseTarget); | |
f9bf01c6 | 109 | |
93a37866 | 110 | // All other cases are unconditional fall-throughs, like "if (true)". |
f9bf01c6 A |
111 | } |
112 | ||
93a37866 | 113 | RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
114 | { |
115 | if (dst == generator.ignoredResult()) | |
116 | return 0; | |
93a37866 | 117 | return generator.emitLoad(dst, jsValue(generator)); |
f9bf01c6 A |
118 | } |
119 | ||
93a37866 | 120 | JSValue StringNode::jsValue(BytecodeGenerator& generator) const |
f9bf01c6 | 121 | { |
93a37866 | 122 | return generator.addStringConstant(m_value); |
f9bf01c6 A |
123 | } |
124 | ||
125 | // ------------------------------ RegExpNode ----------------------------------- | |
126 | ||
127 | RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
128 | { | |
f9bf01c6 A |
129 | if (dst == generator.ignoredResult()) |
130 | return 0; | |
93a37866 | 131 | return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); |
f9bf01c6 A |
132 | } |
133 | ||
134 | // ------------------------------ ThisNode ------------------------------------- | |
135 | ||
136 | RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
137 | { | |
138 | if (dst == generator.ignoredResult()) | |
139 | return 0; | |
140 | return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); | |
141 | } | |
142 | ||
143 | // ------------------------------ ResolveNode ---------------------------------- | |
144 | ||
145 | bool ResolveNode::isPure(BytecodeGenerator& generator) const | |
146 | { | |
81345200 | 147 | return generator.local(m_ident).get(); |
f9bf01c6 A |
148 | } |
149 | ||
150 | RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
151 | { | |
81345200 | 152 | if (Local local = generator.local(m_ident)) { |
f9bf01c6 A |
153 | if (dst == generator.ignoredResult()) |
154 | return 0; | |
81345200 | 155 | return generator.moveToDestinationIfNeeded(dst, local.get()); |
f9bf01c6 A |
156 | } |
157 | ||
81345200 A |
158 | JSTextPosition divot = m_start + m_ident.length(); |
159 | generator.emitExpressionInfo(divot, m_start, divot); | |
160 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); | |
161 | return generator.emitGetFromScope(generator.finalDestination(dst), scope.get(), m_ident, ThrowIfNotFound); | |
f9bf01c6 A |
162 | } |
163 | ||
164 | // ------------------------------ ArrayNode ------------------------------------ | |
165 | ||
166 | RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
167 | { | |
168 | // FIXME: Should we put all of this code into emitNewArray? | |
169 | ||
170 | unsigned length = 0; | |
171 | ElementNode* firstPutElement; | |
172 | for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { | |
81345200 | 173 | if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) |
f9bf01c6 A |
174 | break; |
175 | ++length; | |
176 | } | |
177 | ||
178 | if (!firstPutElement && !m_elision) | |
14957cd0 | 179 | return generator.emitNewArray(generator.finalDestination(dst), m_element, length); |
f9bf01c6 | 180 | |
14957cd0 | 181 | RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element, length); |
81345200 A |
182 | ElementNode* n = firstPutElement; |
183 | for (; n; n = n->next()) { | |
184 | if (n->value()->isSpreadExpression()) | |
185 | goto handleSpread; | |
f9bf01c6 A |
186 | RegisterID* value = generator.emitNode(n->value()); |
187 | length += n->elision(); | |
188 | generator.emitPutByIndex(array.get(), length++, value); | |
189 | } | |
190 | ||
191 | if (m_elision) { | |
14957cd0 | 192 | RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); |
f9bf01c6 A |
193 | generator.emitPutById(array.get(), generator.propertyNames().length, value); |
194 | } | |
195 | ||
196 | return generator.moveToDestinationIfNeeded(dst, array.get()); | |
81345200 A |
197 | |
198 | handleSpread: | |
199 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(length)); | |
200 | auto spreader = [this, array, index](BytecodeGenerator& generator, RegisterID* value) | |
201 | { | |
202 | generator.emitDirectPutByVal(array.get(), index.get(), value); | |
203 | generator.emitInc(index.get()); | |
204 | }; | |
205 | for (; n; n = n->next()) { | |
206 | if (n->elision()) | |
207 | generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(n->elision())), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
208 | if (n->value()->isSpreadExpression()) { | |
209 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(n->value()); | |
210 | generator.emitEnumeration(spread, spread->expression(), spreader); | |
211 | } else { | |
212 | generator.emitDirectPutByVal(array.get(), index.get(), generator.emitNode(n->value())); | |
213 | generator.emitInc(index.get()); | |
214 | } | |
215 | } | |
216 | ||
217 | if (m_elision) { | |
218 | generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(m_elision)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
219 | generator.emitPutById(array.get(), generator.propertyNames().length, index.get()); | |
220 | } | |
221 | return generator.moveToDestinationIfNeeded(dst, array.get()); | |
f9bf01c6 A |
222 | } |
223 | ||
224 | bool ArrayNode::isSimpleArray() const | |
225 | { | |
226 | if (m_elision || m_optional) | |
227 | return false; | |
228 | for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { | |
229 | if (ptr->elision()) | |
230 | return false; | |
231 | } | |
232 | return true; | |
233 | } | |
234 | ||
93a37866 | 235 | ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPosition) const |
f9bf01c6 A |
236 | { |
237 | ASSERT(!m_elision && !m_optional); | |
238 | ElementNode* ptr = m_element; | |
239 | if (!ptr) | |
240 | return 0; | |
93a37866 A |
241 | JSTokenLocation location; |
242 | location.line = lineNumber; | |
243 | location.startOffset = startPosition; | |
244 | ArgumentListNode* head = new (vm) ArgumentListNode(location, ptr->value()); | |
f9bf01c6 A |
245 | ArgumentListNode* tail = head; |
246 | ptr = ptr->next(); | |
247 | for (; ptr; ptr = ptr->next()) { | |
248 | ASSERT(!ptr->elision()); | |
93a37866 | 249 | tail = new (vm) ArgumentListNode(location, tail, ptr->value()); |
f9bf01c6 A |
250 | } |
251 | return head; | |
252 | } | |
253 | ||
254 | // ------------------------------ ObjectLiteralNode ---------------------------- | |
255 | ||
256 | RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
257 | { | |
258 | if (!m_list) { | |
259 | if (dst == generator.ignoredResult()) | |
260 | return 0; | |
261 | return generator.emitNewObject(generator.finalDestination(dst)); | |
262 | } | |
263 | return generator.emitNode(dst, m_list); | |
264 | } | |
265 | ||
266 | // ------------------------------ PropertyListNode ----------------------------- | |
267 | ||
268 | RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
269 | { | |
270 | RefPtr<RegisterID> newObj = generator.tempDestination(dst); | |
271 | ||
272 | generator.emitNewObject(newObj.get()); | |
273 | ||
6fe7ccc8 A |
274 | // Fast case: this loop just handles regular value properties. |
275 | PropertyListNode* p = this; | |
81345200 A |
276 | for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next) { |
277 | if (p->m_node->m_name) { | |
278 | generator.emitDirectPutById(newObj.get(), *p->m_node->name(), generator.emitNode(p->m_node->m_assign)); | |
279 | continue; | |
280 | } | |
281 | RefPtr<RegisterID> propertyName = generator.emitNode(p->m_node->m_expression); | |
282 | generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); | |
283 | } | |
6fe7ccc8 A |
284 | |
285 | // Were there any get/set properties? | |
286 | if (p) { | |
287 | typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair; | |
288 | typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap; | |
289 | GetterSetterMap map; | |
290 | ||
291 | // Build a map, pairing get/set values together. | |
292 | for (PropertyListNode* q = p; q; q = q->m_next) { | |
293 | PropertyNode* node = q->m_node; | |
294 | if (node->m_type == PropertyNode::Constant) | |
295 | continue; | |
296 | ||
297 | GetterSetterPair pair(node, static_cast<PropertyNode*>(0)); | |
81345200 | 298 | GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); |
6fe7ccc8 | 299 | if (!result.isNewEntry) |
93a37866 | 300 | result.iterator->value.second = node; |
6fe7ccc8 A |
301 | } |
302 | ||
303 | // Iterate over the remaining properties in the list. | |
304 | for (; p; p = p->m_next) { | |
305 | PropertyNode* node = p->m_node; | |
6fe7ccc8 A |
306 | |
307 | // Handle regular values. | |
308 | if (node->m_type == PropertyNode::Constant) { | |
81345200 A |
309 | if (node->name()) { |
310 | generator.emitDirectPutById(newObj.get(), *node->name(), generator.emitNode(node->m_assign)); | |
311 | continue; | |
312 | } | |
313 | RefPtr<RegisterID> propertyName = generator.emitNode(p->m_node->m_expression); | |
314 | generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); | |
6fe7ccc8 | 315 | continue; |
f9bf01c6 | 316 | } |
81345200 A |
317 | |
318 | RegisterID* value = generator.emitNode(node->m_assign); | |
6fe7ccc8 A |
319 | |
320 | // This is a get/set property, find its entry in the map. | |
321 | ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter); | |
81345200 | 322 | GetterSetterMap::iterator it = map.find(node->name()->impl()); |
6fe7ccc8 | 323 | ASSERT(it != map.end()); |
93a37866 | 324 | GetterSetterPair& pair = it->value; |
6fe7ccc8 A |
325 | |
326 | // Was this already generated as a part of its partner? | |
327 | if (pair.second == node) | |
328 | continue; | |
329 | ||
330 | // Generate the paired node now. | |
331 | RefPtr<RegisterID> getterReg; | |
332 | RefPtr<RegisterID> setterReg; | |
333 | ||
334 | if (node->m_type == PropertyNode::Getter) { | |
335 | getterReg = value; | |
336 | if (pair.second) { | |
337 | ASSERT(pair.second->m_type == PropertyNode::Setter); | |
338 | setterReg = generator.emitNode(pair.second->m_assign); | |
339 | } else { | |
340 | setterReg = generator.newTemporary(); | |
341 | generator.emitLoad(setterReg.get(), jsUndefined()); | |
342 | } | |
343 | } else { | |
344 | ASSERT(node->m_type == PropertyNode::Setter); | |
345 | setterReg = value; | |
346 | if (pair.second) { | |
347 | ASSERT(pair.second->m_type == PropertyNode::Getter); | |
348 | getterReg = generator.emitNode(pair.second->m_assign); | |
349 | } else { | |
350 | getterReg = generator.newTemporary(); | |
351 | generator.emitLoad(getterReg.get(), jsUndefined()); | |
352 | } | |
f9bf01c6 | 353 | } |
6fe7ccc8 | 354 | |
81345200 | 355 | generator.emitPutGetterSetter(newObj.get(), *node->name(), getterReg.get(), setterReg.get()); |
f9bf01c6 A |
356 | } |
357 | } | |
6fe7ccc8 | 358 | |
f9bf01c6 A |
359 | return generator.moveToDestinationIfNeeded(dst, newObj.get()); |
360 | } | |
361 | ||
362 | // ------------------------------ BracketAccessorNode -------------------------------- | |
363 | ||
364 | RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
365 | { | |
93a37866 A |
366 | if (m_base->isResolveNode() |
367 | && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier()) | |
368 | && !generator.symbolTable().slowArguments()) { | |
40a37d08 | 369 | RefPtr<RegisterID> property = generator.emitNode(m_subscript); |
81345200 | 370 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 371 | return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property.get()); |
14957cd0 A |
372 | } |
373 | ||
f9bf01c6 A |
374 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); |
375 | RegisterID* property = generator.emitNode(m_subscript); | |
81345200 | 376 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
377 | return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); |
378 | } | |
379 | ||
380 | // ------------------------------ DotAccessorNode -------------------------------- | |
381 | ||
382 | RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
383 | { | |
14957cd0 A |
384 | if (m_ident == generator.propertyNames().length) { |
385 | if (!m_base->isResolveNode()) | |
386 | goto nonArgumentsPath; | |
387 | ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base); | |
388 | if (!generator.willResolveToArguments(resolveNode->identifier())) | |
389 | goto nonArgumentsPath; | |
81345200 | 390 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
14957cd0 A |
391 | return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); |
392 | } | |
393 | ||
394 | nonArgumentsPath: | |
40a37d08 | 395 | RefPtr<RegisterID> base = generator.emitNode(m_base); |
81345200 | 396 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 397 | return generator.emitGetById(generator.finalDestination(dst), base.get(), m_ident); |
f9bf01c6 A |
398 | } |
399 | ||
400 | // ------------------------------ ArgumentListNode ----------------------------- | |
401 | ||
402 | RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
403 | { | |
404 | ASSERT(m_expr); | |
405 | return generator.emitNode(dst, m_expr); | |
406 | } | |
407 | ||
408 | // ------------------------------ NewExprNode ---------------------------------- | |
409 | ||
410 | RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
411 | { | |
93a37866 A |
412 | ExpectedFunction expectedFunction; |
413 | if (m_expr->isResolveNode()) | |
414 | expectedFunction = generator.expectedFunctionForIdentifier(static_cast<ResolveNode*>(m_expr)->identifier()); | |
415 | else | |
416 | expectedFunction = NoExpectedFunction; | |
f9bf01c6 | 417 | RefPtr<RegisterID> func = generator.emitNode(m_expr); |
81345200 | 418 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 | 419 | CallArguments callArguments(generator, m_args); |
81345200 | 420 | return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 A |
421 | } |
422 | ||
81345200 | 423 | CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments) |
14957cd0 | 424 | : m_argumentsNode(argumentsNode) |
81345200 | 425 | , m_padding(0) |
14957cd0 A |
426 | { |
427 | if (generator.shouldEmitProfileHooks()) | |
428 | m_profileHookRegister = generator.newTemporary(); | |
6fe7ccc8 | 429 | |
81345200 | 430 | size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register. |
14957cd0 | 431 | if (argumentsNode) { |
6fe7ccc8 A |
432 | for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next) |
433 | ++argumentCountIncludingThis; | |
434 | } | |
435 | ||
436 | m_argv.grow(argumentCountIncludingThis); | |
437 | for (int i = argumentCountIncludingThis - 1; i >= 0; --i) { | |
438 | m_argv[i] = generator.newTemporary(); | |
81345200 A |
439 | ASSERT(static_cast<size_t>(i) == m_argv.size() - 1 || m_argv[i]->index() == m_argv[i + 1]->index() - 1); |
440 | } | |
441 | ||
442 | while (stackOffset() % stackAlignmentRegisters()) { | |
443 | m_argv.insert(0, generator.newTemporary()); | |
444 | m_padding++; | |
14957cd0 | 445 | } |
6fe7ccc8 A |
446 | } |
447 | ||
f9bf01c6 A |
448 | // ------------------------------ EvalFunctionCallNode ---------------------------------- |
449 | ||
450 | RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
451 | { | |
81345200 A |
452 | if (Local local = generator.local(generator.propertyNames().eval)) { |
453 | RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get()); | |
454 | CallArguments callArguments(generator, m_args); | |
455 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
456 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); | |
457 | } | |
458 | ||
459 | RefPtr<RegisterID> func = generator.newTemporary(); | |
14957cd0 | 460 | CallArguments callArguments(generator, m_args); |
81345200 A |
461 | JSTextPosition newDivot = divotStart() + 4; |
462 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
463 | generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval); | |
464 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound); | |
465 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); | |
f9bf01c6 A |
466 | } |
467 | ||
468 | // ------------------------------ FunctionCallValueNode ---------------------------------- | |
469 | ||
470 | RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
471 | { | |
472 | RefPtr<RegisterID> func = generator.emitNode(m_expr); | |
81345200 | 473 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 A |
474 | CallArguments callArguments(generator, m_args); |
475 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
81345200 | 476 | return generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
477 | } |
478 | ||
479 | // ------------------------------ FunctionCallResolveNode ---------------------------------- | |
480 | ||
481 | RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
482 | { | |
93a37866 | 483 | ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); |
93a37866 | 484 | |
81345200 A |
485 | if (Local local = generator.local(m_ident)) { |
486 | RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get()); | |
487 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); | |
14957cd0 A |
488 | CallArguments callArguments(generator, m_args); |
489 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
93a37866 A |
490 | // This passes NoExpectedFunction because we expect that if the function is in a |
491 | // local variable, then it's not one of our built-in constructors. | |
81345200 | 492 | return generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
493 | } |
494 | ||
495 | RefPtr<RegisterID> func = generator.newTemporary(); | |
81345200 | 496 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 | 497 | CallArguments callArguments(generator, m_args); |
93a37866 | 498 | |
81345200 A |
499 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
500 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
501 | generator.emitResolveScope(callArguments.thisRegister(), m_ident); | |
502 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound); | |
503 | return generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
f9bf01c6 A |
504 | } |
505 | ||
506 | // ------------------------------ FunctionCallBracketNode ---------------------------------- | |
507 | ||
508 | RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
509 | { | |
510 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
40a37d08 | 511 | RefPtr<RegisterID> property = generator.emitNode(m_subscript); |
81345200 | 512 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
40a37d08 | 513 | RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
81345200 | 514 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
14957cd0 A |
515 | CallArguments callArguments(generator, m_args); |
516 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
81345200 | 517 | return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
518 | } |
519 | ||
520 | // ------------------------------ FunctionCallDotNode ---------------------------------- | |
521 | ||
522 | RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
523 | { | |
524 | RefPtr<RegisterID> function = generator.tempDestination(dst); | |
81345200 | 525 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
14957cd0 A |
526 | CallArguments callArguments(generator, m_args); |
527 | generator.emitNode(callArguments.thisRegister(), m_base); | |
81345200 | 528 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
14957cd0 | 529 | generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); |
81345200 A |
530 | return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
531 | } | |
532 | ||
533 | static RegisterID* getArgumentByVal(BytecodeGenerator& generator, ExpressionNode* base, RegisterID* property, RegisterID* dst, JSTextPosition divot, JSTextPosition divotStart, JSTextPosition divotEnd) | |
534 | { | |
535 | if (base->isResolveNode() | |
536 | && generator.willResolveToArguments(static_cast<ResolveNode*>(base)->identifier()) | |
537 | && !generator.symbolTable().slowArguments()) { | |
538 | generator.emitExpressionInfo(divot, divotStart, divotEnd); | |
539 | return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); | |
540 | } | |
541 | return nullptr; | |
f9bf01c6 A |
542 | } |
543 | ||
544 | RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
545 | { | |
546 | RefPtr<Label> realCall = generator.newLabel(); | |
547 | RefPtr<Label> end = generator.newLabel(); | |
548 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
81345200 A |
549 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
550 | RefPtr<RegisterID> function; | |
551 | bool emitCallCheck = !generator.isBuiltinFunction(); | |
552 | if (emitCallCheck) { | |
553 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName()); | |
554 | generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); | |
555 | } | |
556 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst); | |
f9bf01c6 | 557 | { |
81345200 A |
558 | if (m_args->m_listNode && m_args->m_listNode->m_expr && m_args->m_listNode->m_expr->isSpreadExpression()) { |
559 | RefPtr<RegisterID> profileHookRegister; | |
560 | if (generator.shouldEmitProfileHooks()) | |
561 | profileHookRegister = generator.newTemporary(); | |
562 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); | |
563 | ExpressionNode* subject = spread->expression(); | |
564 | RefPtr<RegisterID> thisRegister = getArgumentByVal(generator, subject, generator.emitLoad(0, jsNumber(0)), 0, spread->divot(), spread->divotStart(), spread->divotEnd()); | |
565 | RefPtr<RegisterID> argumentsRegister; | |
566 | if (thisRegister) | |
567 | argumentsRegister = generator.uncheckedRegisterForArguments(); | |
568 | else { | |
569 | argumentsRegister = generator.emitNode(subject); | |
570 | generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); | |
571 | thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); | |
572 | } | |
573 | generator.emitCallVarargs(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, profileHookRegister.get(), divot(), divotStart(), divotEnd()); | |
574 | } else if (m_args->m_listNode && m_args->m_listNode->m_expr) { | |
14957cd0 | 575 | ArgumentListNode* oldList = m_args->m_listNode; |
f9bf01c6 | 576 | m_args->m_listNode = m_args->m_listNode->m_next; |
f9bf01c6 | 577 | |
14957cd0 A |
578 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
579 | CallArguments callArguments(generator, m_args); | |
580 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); | |
81345200 | 581 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 | 582 | m_args->m_listNode = oldList; |
14957cd0 A |
583 | } else { |
584 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); | |
585 | CallArguments callArguments(generator, m_args); | |
586 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
81345200 | 587 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 | 588 | } |
f9bf01c6 | 589 | } |
81345200 A |
590 | if (emitCallCheck) { |
591 | generator.emitJump(end.get()); | |
592 | generator.emitLabel(realCall.get()); | |
593 | { | |
594 | CallArguments callArguments(generator, m_args); | |
595 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
596 | generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
597 | } | |
598 | generator.emitLabel(end.get()); | |
f9bf01c6 | 599 | } |
81345200 | 600 | return returnValue.get(); |
f9bf01c6 | 601 | } |
14957cd0 | 602 | |
f9bf01c6 A |
603 | static bool areTrivialApplyArguments(ArgumentsNode* args) |
604 | { | |
605 | return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next | |
606 | || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); | |
607 | } | |
608 | ||
609 | RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
610 | { | |
611 | // A few simple cases can be trivially handled as ordinary function calls. | |
612 | // function.apply(), function.apply(arg) -> identical to function.call | |
613 | // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation | |
614 | bool mayBeCall = areTrivialApplyArguments(m_args); | |
615 | ||
616 | RefPtr<Label> realCall = generator.newLabel(); | |
617 | RefPtr<Label> end = generator.newLabel(); | |
618 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
81345200 A |
619 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
620 | RefPtr<RegisterID> function; | |
621 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); | |
622 | bool emitCallCheck = !generator.isBuiltinFunction(); | |
623 | if (emitCallCheck) { | |
624 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName()); | |
625 | generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); | |
626 | } | |
627 | if (mayBeCall) { | |
628 | if (m_args->m_listNode && m_args->m_listNode->m_expr) { | |
629 | ArgumentListNode* oldList = m_args->m_listNode; | |
630 | if (m_args->m_listNode->m_expr->isSpreadExpression()) { | |
631 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); | |
632 | RefPtr<RegisterID> profileHookRegister; | |
633 | if (generator.shouldEmitProfileHooks()) | |
634 | profileHookRegister = generator.newTemporary(); | |
635 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); | |
636 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(0)); | |
637 | RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); | |
638 | RefPtr<RegisterID> argumentsRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); | |
639 | ||
640 | auto extractor = [&thisRegister, &argumentsRegister, &index](BytecodeGenerator& generator, RegisterID* value) | |
641 | { | |
642 | RefPtr<Label> haveThis = generator.newLabel(); | |
643 | RefPtr<Label> end = generator.newLabel(); | |
644 | RefPtr<RegisterID> compareResult = generator.newTemporary(); | |
645 | RefPtr<RegisterID> indexZeroCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(0)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
646 | generator.emitJumpIfFalse(indexZeroCompareResult.get(), haveThis.get()); | |
647 | generator.emitMove(thisRegister.get(), value); | |
648 | generator.emitLoad(index.get(), jsNumber(1)); | |
649 | generator.emitJump(end.get()); | |
650 | generator.emitLabel(haveThis.get()); | |
651 | RefPtr<RegisterID> indexOneCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(1)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
652 | generator.emitJumpIfFalse(indexOneCompareResult.get(), end.get()); | |
653 | generator.emitMove(argumentsRegister.get(), value); | |
654 | generator.emitLoad(index.get(), jsNumber(2)); | |
655 | generator.emitLabel(end.get()); | |
656 | }; | |
657 | generator.emitEnumeration(this, spread->expression(), extractor); | |
658 | generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd()); | |
659 | } else if (m_args->m_listNode->m_next) { | |
660 | ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); | |
661 | ASSERT(!m_args->m_listNode->m_next->m_next); | |
662 | m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.vm(), 0, 0); | |
663 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); | |
664 | CallArguments callArguments(generator, m_args); | |
665 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); | |
666 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
14957cd0 | 667 | } else { |
81345200 | 668 | m_args->m_listNode = m_args->m_listNode->m_next; |
14957cd0 A |
669 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
670 | CallArguments callArguments(generator, m_args); | |
81345200 A |
671 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
672 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
14957cd0 | 673 | } |
81345200 | 674 | m_args->m_listNode = oldList; |
f9bf01c6 | 675 | } else { |
6fe7ccc8 | 676 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
81345200 A |
677 | CallArguments callArguments(generator, m_args); |
678 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
679 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
f9bf01c6 | 680 | } |
81345200 A |
681 | } else { |
682 | ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); | |
683 | RefPtr<RegisterID> profileHookRegister; | |
684 | if (generator.shouldEmitProfileHooks()) | |
685 | profileHookRegister = generator.newTemporary(); | |
686 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); | |
687 | RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr); | |
688 | RefPtr<RegisterID> argsRegister; | |
689 | ArgumentListNode* args = m_args->m_listNode->m_next; | |
690 | if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(args->m_expr)->identifier()) && !generator.symbolTable().slowArguments()) | |
691 | argsRegister = generator.uncheckedRegisterForArguments(); | |
692 | else | |
693 | argsRegister = generator.emitNode(args->m_expr); | |
694 | ||
695 | // Function.prototype.apply ignores extra arguments, but we still | |
696 | // need to evaluate them for side effects. | |
697 | while ((args = args->m_next)) | |
698 | generator.emitNode(args->m_expr); | |
699 | ||
700 | generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd()); | |
f9bf01c6 | 701 | } |
81345200 A |
702 | if (emitCallCheck) { |
703 | generator.emitJump(end.get()); | |
704 | generator.emitLabel(realCall.get()); | |
14957cd0 A |
705 | CallArguments callArguments(generator, m_args); |
706 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
81345200 A |
707 | generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
708 | generator.emitLabel(end.get()); | |
f9bf01c6 | 709 | } |
81345200 | 710 | return returnValue.get(); |
f9bf01c6 A |
711 | } |
712 | ||
93a37866 | 713 | // ------------------------------ PostfixNode ---------------------------------- |
f9bf01c6 | 714 | |
93a37866 | 715 | static RegisterID* emitIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) |
f9bf01c6 | 716 | { |
93a37866 | 717 | return (oper == OpPlusPlus) ? generator.emitInc(srcDst) : generator.emitDec(srcDst); |
f9bf01c6 A |
718 | } |
719 | ||
720 | static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) | |
721 | { | |
93a37866 A |
722 | if (dst == srcDst) |
723 | return generator.emitToNumber(generator.finalDestination(dst), srcDst); | |
724 | RefPtr<RegisterID> tmp = generator.emitToNumber(generator.tempDestination(dst), srcDst); | |
725 | emitIncOrDec(generator, srcDst, oper); | |
726 | return generator.moveToDestinationIfNeeded(dst, tmp.get()); | |
f9bf01c6 A |
727 | } |
728 | ||
93a37866 | 729 | RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 730 | { |
93a37866 A |
731 | if (dst == generator.ignoredResult()) |
732 | return PrefixNode::emitResolve(generator, dst); | |
f9bf01c6 | 733 | |
93a37866 A |
734 | ASSERT(m_expr->isResolveNode()); |
735 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); | |
736 | const Identifier& ident = resolve->identifier(); | |
f9bf01c6 | 737 | |
81345200 | 738 | if (Local local = generator.local(ident)) { |
40a37d08 | 739 | RefPtr<RegisterID> localReg = local.get(); |
81345200 | 740 | if (local.isReadOnly()) { |
93a37866 | 741 | generator.emitReadOnlyExceptionIfNeeded(); |
40a37d08 | 742 | localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); |
81345200 A |
743 | } else if (local.isCaptured()) { |
744 | RefPtr<RegisterID> tempDst = generator.finalDestination(dst); | |
745 | ASSERT(dst != localReg); | |
746 | RefPtr<RegisterID> tempDstSrc = generator.newTemporary(); | |
40a37d08 A |
747 | generator.emitToNumber(tempDst.get(), localReg.get()); |
748 | generator.emitMove(tempDstSrc.get(), localReg.get()); | |
81345200 | 749 | emitIncOrDec(generator, tempDstSrc.get(), m_operator); |
40a37d08 | 750 | generator.emitMove(localReg.get(), tempDstSrc.get()); |
81345200 | 751 | return tempDst.get(); |
f9bf01c6 | 752 | } |
40a37d08 | 753 | return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); |
f9bf01c6 | 754 | } |
f9bf01c6 | 755 | |
81345200 A |
756 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
757 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), ident); | |
758 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); | |
93a37866 | 759 | RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); |
81345200 | 760 | generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); |
93a37866 A |
761 | return oldValue.get(); |
762 | } | |
f9bf01c6 | 763 | |
93a37866 | 764 | RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 765 | { |
93a37866 A |
766 | if (dst == generator.ignoredResult()) |
767 | return PrefixNode::emitBracket(generator, dst); | |
768 | ||
769 | ASSERT(m_expr->isBracketAccessorNode()); | |
770 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); | |
771 | ExpressionNode* baseNode = bracketAccessor->base(); | |
772 | ExpressionNode* subscript = bracketAccessor->subscript(); | |
773 | ||
774 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); | |
775 | RefPtr<RegisterID> property = generator.emitNode(subscript); | |
f9bf01c6 | 776 | |
81345200 | 777 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
f9bf01c6 | 778 | RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); |
93a37866 | 779 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); |
81345200 | 780 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 781 | generator.emitPutByVal(base.get(), property.get(), value.get()); |
93a37866 | 782 | return generator.moveToDestinationIfNeeded(dst, oldValue); |
f9bf01c6 A |
783 | } |
784 | ||
93a37866 | 785 | RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 786 | { |
93a37866 A |
787 | if (dst == generator.ignoredResult()) |
788 | return PrefixNode::emitDot(generator, dst); | |
f9bf01c6 | 789 | |
93a37866 A |
790 | ASSERT(m_expr->isDotAccessorNode()); |
791 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); | |
792 | ExpressionNode* baseNode = dotAccessor->base(); | |
793 | const Identifier& ident = dotAccessor->identifier(); | |
794 | ||
795 | RefPtr<RegisterID> base = generator.emitNode(baseNode); | |
f9bf01c6 | 796 | |
81345200 | 797 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
93a37866 A |
798 | RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident); |
799 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); | |
81345200 | 800 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 A |
801 | generator.emitPutById(base.get(), ident, value.get()); |
802 | return generator.moveToDestinationIfNeeded(dst, oldValue); | |
803 | } | |
f9bf01c6 | 804 | |
93a37866 | 805 | RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 806 | { |
93a37866 A |
807 | if (m_expr->isResolveNode()) |
808 | return emitResolve(generator, dst); | |
809 | ||
810 | if (m_expr->isBracketAccessorNode()) | |
811 | return emitBracket(generator, dst); | |
812 | ||
813 | if (m_expr->isDotAccessorNode()) | |
814 | return emitDot(generator, dst); | |
815 | ||
14957cd0 | 816 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
f9bf01c6 A |
817 | ? "Postfix ++ operator applied to value that is not a reference." |
818 | : "Postfix -- operator applied to value that is not a reference."); | |
819 | } | |
820 | ||
821 | // ------------------------------ DeleteResolveNode ----------------------------------- | |
822 | ||
823 | RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
824 | { | |
81345200 | 825 | if (generator.local(m_ident).get()) |
f9bf01c6 A |
826 | return generator.emitLoad(generator.finalDestination(dst), false); |
827 | ||
81345200 A |
828 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
829 | RefPtr<RegisterID> base = generator.emitResolveScope(generator.tempDestination(dst), m_ident); | |
830 | return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident); | |
f9bf01c6 A |
831 | } |
832 | ||
833 | // ------------------------------ DeleteBracketNode ----------------------------------- | |
834 | ||
835 | RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
836 | { | |
837 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); | |
40a37d08 | 838 | RefPtr<RegisterID> r1 = generator.emitNode(m_subscript); |
f9bf01c6 | 839 | |
81345200 | 840 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 841 | return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get()); |
f9bf01c6 A |
842 | } |
843 | ||
844 | // ------------------------------ DeleteDotNode ----------------------------------- | |
845 | ||
846 | RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
847 | { | |
40a37d08 | 848 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); |
f9bf01c6 | 849 | |
81345200 | 850 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 851 | return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident); |
f9bf01c6 A |
852 | } |
853 | ||
854 | // ------------------------------ DeleteValueNode ----------------------------------- | |
855 | ||
856 | RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
857 | { | |
858 | generator.emitNode(generator.ignoredResult(), m_expr); | |
859 | ||
860 | // delete on a non-location expression ignores the value and returns true | |
861 | return generator.emitLoad(generator.finalDestination(dst), true); | |
862 | } | |
863 | ||
864 | // ------------------------------ VoidNode ------------------------------------- | |
865 | ||
866 | RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
867 | { | |
868 | if (dst == generator.ignoredResult()) { | |
869 | generator.emitNode(generator.ignoredResult(), m_expr); | |
870 | return 0; | |
871 | } | |
872 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); | |
873 | return generator.emitLoad(dst, jsUndefined()); | |
874 | } | |
875 | ||
876 | // ------------------------------ TypeOfValueNode ----------------------------------- | |
877 | ||
878 | RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
879 | { | |
81345200 | 880 | if (Local local = generator.local(m_ident)) { |
f9bf01c6 A |
881 | if (dst == generator.ignoredResult()) |
882 | return 0; | |
81345200 | 883 | return generator.emitTypeOf(generator.finalDestination(dst), local.get()); |
93a37866 A |
884 | } |
885 | ||
81345200 A |
886 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); |
887 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound); | |
f9bf01c6 A |
888 | if (dst == generator.ignoredResult()) |
889 | return 0; | |
81345200 | 890 | return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get()); |
f9bf01c6 A |
891 | } |
892 | ||
893 | // ------------------------------ TypeOfValueNode ----------------------------------- | |
894 | ||
895 | RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
896 | { | |
897 | if (dst == generator.ignoredResult()) { | |
898 | generator.emitNode(generator.ignoredResult(), m_expr); | |
899 | return 0; | |
900 | } | |
901 | RefPtr<RegisterID> src = generator.emitNode(m_expr); | |
902 | return generator.emitTypeOf(generator.finalDestination(dst), src.get()); | |
903 | } | |
904 | ||
93a37866 | 905 | // ------------------------------ PrefixNode ---------------------------------- |
f9bf01c6 | 906 | |
93a37866 | 907 | RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 908 | { |
93a37866 A |
909 | ASSERT(m_expr->isResolveNode()); |
910 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); | |
911 | const Identifier& ident = resolve->identifier(); | |
f9bf01c6 | 912 | |
81345200 | 913 | if (Local local = generator.local(ident)) { |
40a37d08 | 914 | RefPtr<RegisterID> localReg = local.get(); |
81345200 | 915 | if (local.isReadOnly()) { |
93a37866 | 916 | generator.emitReadOnlyExceptionIfNeeded(); |
40a37d08 | 917 | localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); |
81345200 A |
918 | } else if (local.isCaptured()) { |
919 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); | |
40a37d08 | 920 | generator.emitMove(tempDst.get(), localReg.get()); |
81345200 | 921 | emitIncOrDec(generator, tempDst.get(), m_operator); |
40a37d08 | 922 | generator.emitMove(localReg.get(), tempDst.get()); |
81345200 | 923 | return generator.moveToDestinationIfNeeded(dst, tempDst.get()); |
93a37866 | 924 | } |
40a37d08 A |
925 | emitIncOrDec(generator, localReg.get(), m_operator); |
926 | return generator.moveToDestinationIfNeeded(dst, localReg.get()); | |
f9bf01c6 A |
927 | } |
928 | ||
81345200 A |
929 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
930 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), ident); | |
931 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); | |
932 | emitIncOrDec(generator, value.get(), m_operator); | |
933 | generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); | |
934 | return generator.moveToDestinationIfNeeded(dst, value.get()); | |
f9bf01c6 A |
935 | } |
936 | ||
93a37866 | 937 | RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 938 | { |
93a37866 A |
939 | ASSERT(m_expr->isBracketAccessorNode()); |
940 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); | |
941 | ExpressionNode* baseNode = bracketAccessor->base(); | |
942 | ExpressionNode* subscript = bracketAccessor->subscript(); | |
943 | ||
944 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); | |
945 | RefPtr<RegisterID> property = generator.emitNode(subscript); | |
f9bf01c6 A |
946 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
947 | ||
81345200 | 948 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
f9bf01c6 | 949 | RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); |
93a37866 | 950 | emitIncOrDec(generator, value, m_operator); |
81345200 | 951 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
952 | generator.emitPutByVal(base.get(), property.get(), value); |
953 | return generator.moveToDestinationIfNeeded(dst, propDst.get()); | |
954 | } | |
955 | ||
93a37866 | 956 | RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 957 | { |
93a37866 A |
958 | ASSERT(m_expr->isDotAccessorNode()); |
959 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); | |
960 | ExpressionNode* baseNode = dotAccessor->base(); | |
961 | const Identifier& ident = dotAccessor->identifier(); | |
962 | ||
963 | RefPtr<RegisterID> base = generator.emitNode(baseNode); | |
f9bf01c6 A |
964 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
965 | ||
81345200 | 966 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
93a37866 A |
967 | RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident); |
968 | emitIncOrDec(generator, value, m_operator); | |
81345200 | 969 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 970 | generator.emitPutById(base.get(), ident, value); |
f9bf01c6 A |
971 | return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
972 | } | |
973 | ||
93a37866 | 974 | RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 975 | { |
93a37866 A |
976 | if (m_expr->isResolveNode()) |
977 | return emitResolve(generator, dst); | |
978 | ||
979 | if (m_expr->isBracketAccessorNode()) | |
980 | return emitBracket(generator, dst); | |
981 | ||
982 | if (m_expr->isDotAccessorNode()) | |
983 | return emitDot(generator, dst); | |
984 | ||
14957cd0 | 985 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
f9bf01c6 A |
986 | ? "Prefix ++ operator applied to value that is not a reference." |
987 | : "Prefix -- operator applied to value that is not a reference."); | |
988 | } | |
989 | ||
990 | // ------------------------------ Unary Operation Nodes ----------------------------------- | |
991 | ||
992 | RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
993 | { | |
40a37d08 | 994 | RefPtr<RegisterID> src = generator.emitNode(m_expr); |
81345200 | 995 | generator.emitExpressionInfo(position(), position(), position()); |
40a37d08 | 996 | return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get()); |
f9bf01c6 A |
997 | } |
998 | ||
6fe7ccc8 A |
999 | // ------------------------------ BitwiseNotNode ----------------------------------- |
1000 | ||
1001 | RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1002 | { | |
1003 | RefPtr<RegisterID> src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1)); | |
40a37d08 A |
1004 | RefPtr<RegisterID> src1 = generator.emitNode(m_expr); |
1005 | return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32())); | |
6fe7ccc8 A |
1006 | } |
1007 | ||
f9bf01c6 A |
1008 | // ------------------------------ LogicalNotNode ----------------------------------- |
1009 | ||
93a37866 | 1010 | void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 1011 | { |
f9bf01c6 | 1012 | // reverse the true and false targets |
93a37866 | 1013 | generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode)); |
f9bf01c6 A |
1014 | } |
1015 | ||
1016 | ||
1017 | // ------------------------------ Binary Operation Nodes ----------------------------------- | |
1018 | ||
1019 | // BinaryOpNode::emitStrcat: | |
1020 | // | |
1021 | // This node generates an op_strcat operation. This opcode can handle concatenation of three or | |
1022 | // more values, where we can determine a set of separate op_add operations would be operating on | |
1023 | // string values. | |
1024 | // | |
1025 | // This function expects to be operating on a graph of AST nodes looking something like this: | |
1026 | // | |
1027 | // (a)... (b) | |
1028 | // \ / | |
1029 | // (+) (c) | |
1030 | // \ / | |
1031 | // [d] ((+)) | |
1032 | // \ / | |
1033 | // [+=] | |
1034 | // | |
1035 | // The assignment operation is optional, if it exists the register holding the value on the | |
1036 | // lefthand side of the assignment should be passing as the optional 'lhs' argument. | |
1037 | // | |
1038 | // The method should be called on the node at the root of the tree of regular binary add | |
1039 | // operations (marked in the diagram with a double set of parentheses). This node must | |
1040 | // be performing a string concatenation (determined by statically detecting that at least | |
1041 | // one child must be a string). | |
1042 | // | |
1043 | // Since the minimum number of values being concatenated together is expected to be 3, if | |
1044 | // a lhs to a concatenating assignment is not provided then the root add should have at | |
1045 | // least one left child that is also an add that can be determined to be operating on strings. | |
1046 | // | |
1047 | RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) | |
1048 | { | |
1049 | ASSERT(isAdd()); | |
1050 | ASSERT(resultDescriptor().definitelyIsString()); | |
1051 | ||
1052 | // Create a list of expressions for all the adds in the tree of nodes we can convert into | |
1053 | // a string concatenation. The rightmost node (c) is added first. The rightmost node is | |
1054 | // added first, and the leftmost child is never added, so the vector produced for the | |
1055 | // example above will be [ c, b ]. | |
1056 | Vector<ExpressionNode*, 16> reverseExpressionList; | |
1057 | reverseExpressionList.append(m_expr2); | |
1058 | ||
1059 | // Examine the left child of the add. So long as this is a string add, add its right-child | |
1060 | // to the list, and keep processing along the left fork. | |
1061 | ExpressionNode* leftMostAddChild = m_expr1; | |
1062 | while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { | |
1063 | reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); | |
1064 | leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; | |
1065 | } | |
1066 | ||
1067 | Vector<RefPtr<RegisterID>, 16> temporaryRegisters; | |
1068 | ||
1069 | // If there is an assignment, allocate a temporary to hold the lhs after conversion. | |
1070 | // We could possibly avoid this (the lhs is converted last anyway, we could let the | |
1071 | // op_strcat node handle its conversion if required). | |
1072 | if (lhs) | |
1073 | temporaryRegisters.append(generator.newTemporary()); | |
1074 | ||
1075 | // Emit code for the leftmost node ((a) in the example). | |
1076 | temporaryRegisters.append(generator.newTemporary()); | |
1077 | RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); | |
1078 | generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); | |
1079 | ||
1080 | // Note on ordering of conversions: | |
1081 | // | |
1082 | // We maintain the same ordering of conversions as we would see if the concatenations | |
1083 | // was performed as a sequence of adds (otherwise this optimization could change | |
1084 | // behaviour should an object have been provided a valueOf or toString method). | |
1085 | // | |
1086 | // Considering the above example, the sequnce of execution is: | |
1087 | // * evaluate operand (a) | |
1088 | // * evaluate operand (b) | |
1089 | // * convert (a) to primitive <- (this would be triggered by the first add) | |
1090 | // * convert (b) to primitive <- (ditto) | |
1091 | // * evaluate operand (c) | |
1092 | // * convert (c) to primitive <- (this would be triggered by the second add) | |
1093 | // And optionally, if there is an assignment: | |
1094 | // * convert (d) to primitive <- (this would be triggered by the assigning addition) | |
1095 | // | |
1096 | // As such we do not plant an op to convert the leftmost child now. Instead, use | |
1097 | // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion | |
1098 | // once the second node has been generated. However, if the leftmost child is an | |
1099 | // immediate we can trivially determine that no conversion will be required. | |
1100 | // If this is the case | |
1101 | if (leftMostAddChild->isString()) | |
1102 | leftMostAddChildTempRegister = 0; | |
1103 | ||
1104 | while (reverseExpressionList.size()) { | |
1105 | ExpressionNode* node = reverseExpressionList.last(); | |
1106 | reverseExpressionList.removeLast(); | |
1107 | ||
1108 | // Emit the code for the current node. | |
1109 | temporaryRegisters.append(generator.newTemporary()); | |
1110 | generator.emitNode(temporaryRegisters.last().get(), node); | |
1111 | ||
1112 | // On the first iteration of this loop, when we first reach this point we have just | |
1113 | // generated the second node, which means it is time to convert the leftmost operand. | |
1114 | if (leftMostAddChildTempRegister) { | |
1115 | generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); | |
1116 | leftMostAddChildTempRegister = 0; // Only do this once. | |
1117 | } | |
1118 | // Plant a conversion for this node, if necessary. | |
1119 | if (!node->isString()) | |
1120 | generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); | |
1121 | } | |
1122 | ASSERT(temporaryRegisters.size() >= 3); | |
1123 | ||
1124 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. | |
1125 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. | |
1126 | if (emitExpressionInfoForMe) | |
81345200 | 1127 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
f9bf01c6 A |
1128 | // If there is an assignment convert the lhs now. This will also copy lhs to |
1129 | // the temporary register we allocated for it. | |
1130 | if (lhs) | |
1131 | generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); | |
1132 | ||
1133 | return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); | |
1134 | } | |
1135 | ||
93a37866 A |
1136 | void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
1137 | { | |
1138 | TriState branchCondition; | |
1139 | ExpressionNode* branchExpression; | |
1140 | tryFoldToBranch(generator, branchCondition, branchExpression); | |
1141 | ||
1142 | if (branchCondition == MixedTriState) | |
1143 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); | |
1144 | else if (branchCondition == TrueTriState) | |
1145 | generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode); | |
1146 | else | |
1147 | generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode)); | |
1148 | } | |
1149 | ||
1150 | static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant) | |
1151 | { | |
1152 | ResultType expressionType = branchExpression->resultDescriptor(); | |
1153 | ||
1154 | if (expressionType.definitelyIsBoolean() && constant.isBoolean()) | |
1155 | return true; | |
1156 | else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1)) | |
1157 | return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch. | |
1158 | else if (expressionType.isInt32() && constant.isInt32() && constant.asInt32() == 0) | |
1159 | return true; | |
1160 | ||
1161 | return false; | |
1162 | } | |
1163 | ||
1164 | void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression) | |
1165 | { | |
1166 | branchCondition = MixedTriState; | |
1167 | branchExpression = 0; | |
1168 | ||
1169 | ConstantNode* constant = 0; | |
1170 | if (m_expr1->isConstant()) { | |
1171 | constant = static_cast<ConstantNode*>(m_expr1); | |
1172 | branchExpression = m_expr2; | |
1173 | } else if (m_expr2->isConstant()) { | |
1174 | constant = static_cast<ConstantNode*>(m_expr2); | |
1175 | branchExpression = m_expr1; | |
1176 | } | |
1177 | ||
1178 | if (!constant) | |
1179 | return; | |
1180 | ASSERT(branchExpression); | |
1181 | ||
1182 | OpcodeID opcodeID = this->opcodeID(); | |
1183 | JSValue value = constant->jsValue(generator); | |
1184 | bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value); | |
1185 | if (!canFoldToBranch) | |
1186 | return; | |
1187 | ||
1188 | if (opcodeID == op_eq || opcodeID == op_stricteq) | |
1189 | branchCondition = triState(value.pureToBoolean()); | |
1190 | else if (opcodeID == op_neq || opcodeID == op_nstricteq) | |
1191 | branchCondition = triState(!value.pureToBoolean()); | |
1192 | } | |
1193 | ||
f9bf01c6 A |
1194 | RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1195 | { | |
1196 | OpcodeID opcodeID = this->opcodeID(); | |
1197 | ||
81345200 A |
1198 | if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { |
1199 | generator.emitExpressionInfo(position(), position(), position()); | |
f9bf01c6 | 1200 | return emitStrcat(generator, dst); |
81345200 | 1201 | } |
f9bf01c6 A |
1202 | |
1203 | if (opcodeID == op_neq) { | |
1204 | if (m_expr1->isNull() || m_expr2->isNull()) { | |
1205 | RefPtr<RegisterID> src = generator.tempDestination(dst); | |
1206 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); | |
1207 | return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); | |
1208 | } | |
1209 | } | |
1210 | ||
93a37866 A |
1211 | ExpressionNode* left = m_expr1; |
1212 | ExpressionNode* right = m_expr2; | |
1213 | if (opcodeID == op_neq || opcodeID == op_nstricteq) { | |
1214 | if (left->isString()) | |
1215 | std::swap(left, right); | |
1216 | } | |
1217 | ||
1218 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); | |
1219 | bool wasTypeof = generator.m_lastOpcodeID == op_typeof; | |
40a37d08 | 1220 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
81345200 | 1221 | generator.emitExpressionInfo(position(), position(), position()); |
93a37866 A |
1222 | if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { |
1223 | RefPtr<RegisterID> tmp = generator.tempDestination(dst); | |
1224 | if (opcodeID == op_neq) | |
40a37d08 | 1225 | generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
93a37866 | 1226 | else if (opcodeID == op_nstricteq) |
40a37d08 | 1227 | generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
93a37866 A |
1228 | else |
1229 | RELEASE_ASSERT_NOT_REACHED(); | |
1230 | return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get()); | |
1231 | } | |
40a37d08 | 1232 | RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor())); |
81345200 A |
1233 | if (opcodeID == op_urshift && dst != generator.ignoredResult()) |
1234 | return generator.emitUnaryOp(op_unsigned, result, result); | |
1235 | return result; | |
f9bf01c6 A |
1236 | } |
1237 | ||
1238 | RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1239 | { | |
1240 | if (m_expr1->isNull() || m_expr2->isNull()) { | |
1241 | RefPtr<RegisterID> src = generator.tempDestination(dst); | |
1242 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); | |
1243 | return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); | |
1244 | } | |
1245 | ||
93a37866 A |
1246 | ExpressionNode* left = m_expr1; |
1247 | ExpressionNode* right = m_expr2; | |
1248 | if (left->isString()) | |
1249 | std::swap(left, right); | |
1250 | ||
1251 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 A |
1252 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
1253 | return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); | |
f9bf01c6 A |
1254 | } |
1255 | ||
1256 | RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1257 | { | |
93a37866 A |
1258 | ExpressionNode* left = m_expr1; |
1259 | ExpressionNode* right = m_expr2; | |
1260 | if (left->isString()) | |
1261 | std::swap(left, right); | |
1262 | ||
1263 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 A |
1264 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
1265 | return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); | |
f9bf01c6 A |
1266 | } |
1267 | ||
f9bf01c6 A |
1268 | RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1269 | { | |
1270 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 | 1271 | RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); |
81345200 | 1272 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1273 | return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); |
f9bf01c6 A |
1274 | } |
1275 | ||
1276 | RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1277 | { | |
1278 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); | |
1279 | RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); | |
93a37866 A |
1280 | RefPtr<RegisterID> prototype = generator.newTemporary(); |
1281 | RefPtr<RegisterID> dstReg = generator.finalDestination(dst, src1.get()); | |
1282 | RefPtr<Label> target = generator.newLabel(); | |
f9bf01c6 | 1283 | |
81345200 | 1284 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1285 | generator.emitCheckHasInstance(dstReg.get(), src1.get(), src2.get(), target.get()); |
14957cd0 | 1286 | |
81345200 | 1287 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1288 | generator.emitGetById(prototype.get(), src2.get(), generator.vm()->propertyNames->prototype); |
f9bf01c6 | 1289 | |
81345200 | 1290 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 A |
1291 | RegisterID* result = generator.emitInstanceOf(dstReg.get(), src1.get(), prototype.get()); |
1292 | generator.emitLabel(target.get()); | |
1293 | return result; | |
f9bf01c6 A |
1294 | } |
1295 | ||
1296 | // ------------------------------ LogicalOpNode ---------------------------- | |
1297 | ||
1298 | RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1299 | { | |
1300 | RefPtr<RegisterID> temp = generator.tempDestination(dst); | |
1301 | RefPtr<Label> target = generator.newLabel(); | |
1302 | ||
1303 | generator.emitNode(temp.get(), m_expr1); | |
1304 | if (m_operator == OpLogicalAnd) | |
1305 | generator.emitJumpIfFalse(temp.get(), target.get()); | |
1306 | else | |
1307 | generator.emitJumpIfTrue(temp.get(), target.get()); | |
1308 | generator.emitNode(temp.get(), m_expr2); | |
1309 | generator.emitLabel(target.get()); | |
1310 | ||
1311 | return generator.moveToDestinationIfNeeded(dst, temp.get()); | |
1312 | } | |
1313 | ||
93a37866 | 1314 | void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 1315 | { |
93a37866 A |
1316 | RefPtr<Label> afterExpr1 = generator.newLabel(); |
1317 | if (m_operator == OpLogicalAnd) | |
1318 | generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, FallThroughMeansTrue); | |
1319 | else | |
1320 | generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), FallThroughMeansFalse); | |
1321 | generator.emitLabel(afterExpr1.get()); | |
f9bf01c6 | 1322 | |
93a37866 | 1323 | generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMode); |
f9bf01c6 A |
1324 | } |
1325 | ||
1326 | // ------------------------------ ConditionalNode ------------------------------ | |
1327 | ||
1328 | RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1329 | { | |
1330 | RefPtr<RegisterID> newDst = generator.finalDestination(dst); | |
1331 | RefPtr<Label> beforeElse = generator.newLabel(); | |
1332 | RefPtr<Label> afterElse = generator.newLabel(); | |
1333 | ||
93a37866 A |
1334 | RefPtr<Label> beforeThen = generator.newLabel(); |
1335 | generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); | |
1336 | generator.emitLabel(beforeThen.get()); | |
f9bf01c6 A |
1337 | |
1338 | generator.emitNode(newDst.get(), m_expr1); | |
1339 | generator.emitJump(afterElse.get()); | |
1340 | ||
1341 | generator.emitLabel(beforeElse.get()); | |
1342 | generator.emitNode(newDst.get(), m_expr2); | |
1343 | ||
1344 | generator.emitLabel(afterElse.get()); | |
1345 | ||
1346 | return newDst.get(); | |
1347 | } | |
1348 | ||
1349 | // ------------------------------ ReadModifyResolveNode ----------------------------------- | |
1350 | ||
1351 | // FIXME: should this be moved to be a method on BytecodeGenerator? | |
1352 | static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) | |
1353 | { | |
1354 | OpcodeID opcodeID; | |
1355 | switch (oper) { | |
1356 | case OpMultEq: | |
1357 | opcodeID = op_mul; | |
1358 | break; | |
1359 | case OpDivEq: | |
1360 | opcodeID = op_div; | |
1361 | break; | |
1362 | case OpPlusEq: | |
1363 | if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) | |
1364 | return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); | |
1365 | opcodeID = op_add; | |
1366 | break; | |
1367 | case OpMinusEq: | |
1368 | opcodeID = op_sub; | |
1369 | break; | |
1370 | case OpLShift: | |
1371 | opcodeID = op_lshift; | |
1372 | break; | |
1373 | case OpRShift: | |
1374 | opcodeID = op_rshift; | |
1375 | break; | |
1376 | case OpURShift: | |
1377 | opcodeID = op_urshift; | |
1378 | break; | |
1379 | case OpAndEq: | |
1380 | opcodeID = op_bitand; | |
1381 | break; | |
1382 | case OpXOrEq: | |
1383 | opcodeID = op_bitxor; | |
1384 | break; | |
1385 | case OpOrEq: | |
1386 | opcodeID = op_bitor; | |
1387 | break; | |
1388 | case OpModEq: | |
1389 | opcodeID = op_mod; | |
1390 | break; | |
1391 | default: | |
93a37866 | 1392 | RELEASE_ASSERT_NOT_REACHED(); |
f9bf01c6 A |
1393 | return dst; |
1394 | } | |
1395 | ||
1396 | RegisterID* src2 = generator.emitNode(m_right); | |
1397 | ||
1398 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. | |
1399 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. | |
1400 | if (emitExpressionInfoForMe) | |
81345200 A |
1401 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
1402 | RegisterID* result = generator.emitBinaryOp(opcodeID, dst, src1, src2, types); | |
1403 | if (oper == OpURShift) | |
1404 | return generator.emitUnaryOp(op_unsigned, result, result); | |
1405 | return result; | |
f9bf01c6 A |
1406 | } |
1407 | ||
1408 | RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1409 | { | |
81345200 A |
1410 | if (Local local = generator.local(m_ident)) { |
1411 | if (local.isReadOnly()) { | |
93a37866 | 1412 | generator.emitReadOnlyExceptionIfNeeded(); |
81345200 | 1413 | return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
93a37866 A |
1414 | } |
1415 | ||
81345200 A |
1416 | if (local.isCaptured() |
1417 | || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { | |
f9bf01c6 | 1418 | RefPtr<RegisterID> result = generator.newTemporary(); |
81345200 | 1419 | generator.emitMove(result.get(), local.get()); |
f9bf01c6 | 1420 | emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
81345200 | 1421 | generator.emitMove(local.get(), result.get()); |
f9bf01c6 A |
1422 | return generator.moveToDestinationIfNeeded(dst, result.get()); |
1423 | } | |
1424 | ||
81345200 | 1425 | RegisterID* result = emitReadModifyAssignment(generator, local.get(), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
f9bf01c6 A |
1426 | return generator.moveToDestinationIfNeeded(dst, result); |
1427 | } | |
1428 | ||
81345200 A |
1429 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
1430 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
1431 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); | |
1432 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound); | |
1433 | RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); | |
1434 | return generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound); | |
f9bf01c6 A |
1435 | } |
1436 | ||
1437 | // ------------------------------ AssignResolveNode ----------------------------------- | |
1438 | ||
1439 | RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1440 | { | |
81345200 A |
1441 | if (Local local = generator.local(m_ident)) { |
1442 | if (local.isReadOnly()) { | |
93a37866 | 1443 | generator.emitReadOnlyExceptionIfNeeded(); |
f9bf01c6 | 1444 | return generator.emitNode(dst, m_right); |
93a37866 | 1445 | } |
81345200 A |
1446 | if (local.isCaptured()) { |
1447 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); | |
1448 | generator.emitNode(tempDst.get(), m_right); | |
1449 | generator.emitMove(local.get(), tempDst.get()); | |
1450 | return generator.moveToDestinationIfNeeded(dst, tempDst.get()); | |
1451 | } | |
1452 | RegisterID* result = generator.emitNode(local.get(), m_right); | |
f9bf01c6 A |
1453 | return generator.moveToDestinationIfNeeded(dst, result); |
1454 | } | |
1455 | ||
81345200 A |
1456 | if (generator.isStrictMode()) |
1457 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1458 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); | |
f9bf01c6 A |
1459 | if (dst == generator.ignoredResult()) |
1460 | dst = 0; | |
81345200 A |
1461 | RefPtr<RegisterID> result = generator.emitNode(dst, m_right); |
1462 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1463 | return generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); | |
f9bf01c6 A |
1464 | } |
1465 | ||
1466 | // ------------------------------ AssignDotNode ----------------------------------- | |
1467 | ||
1468 | RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1469 | { | |
1470 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); | |
1471 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); | |
40a37d08 | 1472 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
81345200 | 1473 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1474 | RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); |
6fe7ccc8 A |
1475 | generator.emitPutById(base.get(), m_ident, forwardResult); |
1476 | return generator.moveToDestinationIfNeeded(dst, forwardResult); | |
f9bf01c6 A |
1477 | } |
1478 | ||
1479 | // ------------------------------ ReadModifyDotNode ----------------------------------- | |
1480 | ||
1481 | RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1482 | { | |
1483 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); | |
1484 | ||
81345200 | 1485 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
f9bf01c6 | 1486 | RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
81345200 | 1487 | RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
f9bf01c6 | 1488 | |
81345200 | 1489 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
1490 | return generator.emitPutById(base.get(), m_ident, updatedValue); |
1491 | } | |
1492 | ||
1493 | // ------------------------------ AssignErrorNode ----------------------------------- | |
1494 | ||
1495 | RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
1496 | { | |
14957cd0 | 1497 | return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); |
f9bf01c6 A |
1498 | } |
1499 | ||
1500 | // ------------------------------ AssignBracketNode ----------------------------------- | |
1501 | ||
1502 | RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1503 | { | |
1504 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); | |
1505 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); | |
1506 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); | |
40a37d08 | 1507 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
f9bf01c6 | 1508 | |
81345200 | 1509 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1510 | RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); |
6fe7ccc8 A |
1511 | generator.emitPutByVal(base.get(), property.get(), forwardResult); |
1512 | return generator.moveToDestinationIfNeeded(dst, forwardResult); | |
f9bf01c6 A |
1513 | } |
1514 | ||
1515 | // ------------------------------ ReadModifyBracketNode ----------------------------------- | |
1516 | ||
1517 | RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1518 | { | |
1519 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); | |
1520 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); | |
1521 | ||
81345200 | 1522 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
f9bf01c6 | 1523 | RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
81345200 | 1524 | RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
f9bf01c6 | 1525 | |
81345200 | 1526 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
1527 | generator.emitPutByVal(base.get(), property.get(), updatedValue); |
1528 | ||
1529 | return updatedValue; | |
1530 | } | |
1531 | ||
1532 | // ------------------------------ CommaNode ------------------------------------ | |
1533 | ||
1534 | RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1535 | { | |
1536 | ASSERT(m_expressions.size() > 1); | |
1537 | for (size_t i = 0; i < m_expressions.size() - 1; i++) | |
1538 | generator.emitNode(generator.ignoredResult(), m_expressions[i]); | |
1539 | return generator.emitNode(dst, m_expressions.last()); | |
1540 | } | |
1541 | ||
1542 | // ------------------------------ ConstDeclNode ------------------------------------ | |
1543 | ||
1544 | RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) | |
1545 | { | |
6fe7ccc8 | 1546 | // FIXME: This code does not match the behavior of const in Firefox. |
81345200 | 1547 | if (Local local = generator.constLocal(m_ident)) { |
f9bf01c6 | 1548 | if (!m_init) |
81345200 | 1549 | return local.get(); |
f9bf01c6 | 1550 | |
81345200 A |
1551 | if (local.isCaptured()) { |
1552 | RefPtr<RegisterID> tempDst = generator.newTemporary(); | |
1553 | generator.emitNode(tempDst.get(), m_init); | |
1554 | return generator.emitMove(local.get(), tempDst.get()); | |
1555 | } | |
1556 | ||
1557 | return generator.emitNode(local.get(), m_init); | |
f9bf01c6 A |
1558 | } |
1559 | ||
6fe7ccc8 A |
1560 | RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); |
1561 | ||
93a37866 A |
1562 | if (generator.codeType() == GlobalCode) |
1563 | return generator.emitInitGlobalConst(m_ident, value.get()); | |
6fe7ccc8 A |
1564 | |
1565 | if (generator.codeType() != EvalCode) | |
1566 | return value.get(); | |
1567 | ||
93a37866 | 1568 | // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope. |
81345200 A |
1569 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); |
1570 | return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound); | |
f9bf01c6 A |
1571 | } |
1572 | ||
1573 | RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
1574 | { | |
1575 | RegisterID* result = 0; | |
1576 | for (ConstDeclNode* n = this; n; n = n->m_next) | |
1577 | result = n->emitCodeSingle(generator); | |
1578 | ||
1579 | return result; | |
1580 | } | |
1581 | ||
1582 | // ------------------------------ ConstStatementNode ----------------------------- | |
1583 | ||
93a37866 | 1584 | void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 1585 | { |
81345200 | 1586 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 1587 | generator.emitNode(m_next); |
f9bf01c6 A |
1588 | } |
1589 | ||
1590 | // ------------------------------ SourceElements ------------------------------- | |
1591 | ||
1592 | ||
1593 | inline StatementNode* SourceElements::lastStatement() const | |
1594 | { | |
1595 | size_t size = m_statements.size(); | |
1596 | return size ? m_statements[size - 1] : 0; | |
1597 | } | |
1598 | ||
1599 | inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1600 | { | |
1601 | size_t size = m_statements.size(); | |
1602 | for (size_t i = 0; i < size; ++i) | |
1603 | generator.emitNode(dst, m_statements[i]); | |
1604 | } | |
1605 | ||
1606 | // ------------------------------ BlockNode ------------------------------------ | |
1607 | ||
1608 | inline StatementNode* BlockNode::lastStatement() const | |
1609 | { | |
1610 | return m_statements ? m_statements->lastStatement() : 0; | |
1611 | } | |
1612 | ||
14957cd0 A |
1613 | inline StatementNode* BlockNode::singleStatement() const |
1614 | { | |
1615 | return m_statements ? m_statements->singleStatement() : 0; | |
1616 | } | |
1617 | ||
93a37866 | 1618 | void BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1619 | { |
93a37866 A |
1620 | if (!m_statements) |
1621 | return; | |
1622 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
1623 | } |
1624 | ||
1625 | // ------------------------------ EmptyStatementNode --------------------------- | |
1626 | ||
93a37866 | 1627 | void EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 1628 | { |
81345200 | 1629 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
1630 | } |
1631 | ||
1632 | // ------------------------------ DebuggerStatementNode --------------------------- | |
1633 | ||
93a37866 | 1634 | void DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 1635 | { |
81345200 | 1636 | generator.emitDebugHook(DidReachBreakpoint, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
1637 | } |
1638 | ||
1639 | // ------------------------------ ExprStatementNode ---------------------------- | |
1640 | ||
93a37866 | 1641 | void ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
1642 | { |
1643 | ASSERT(m_expr); | |
81345200 | 1644 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 1645 | generator.emitNode(dst, m_expr); |
f9bf01c6 A |
1646 | } |
1647 | ||
1648 | // ------------------------------ VarStatementNode ---------------------------- | |
1649 | ||
93a37866 | 1650 | void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 A |
1651 | { |
1652 | ASSERT(m_expr); | |
81345200 | 1653 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 1654 | generator.emitNode(m_expr); |
f9bf01c6 A |
1655 | } |
1656 | ||
93a37866 | 1657 | // ------------------------------ IfElseNode --------------------------------------- |
f9bf01c6 | 1658 | |
93a37866 | 1659 | static inline StatementNode* singleStatement(StatementNode* statementNode) |
f9bf01c6 | 1660 | { |
93a37866 A |
1661 | if (statementNode->isBlock()) |
1662 | return static_cast<BlockNode*>(statementNode)->singleStatement(); | |
1663 | return statementNode; | |
1664 | } | |
f9bf01c6 | 1665 | |
93a37866 A |
1666 | bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock, |
1667 | Label*& trueTarget, FallThroughMode& fallThroughMode) | |
1668 | { | |
1669 | StatementNode* singleStatement = JSC::singleStatement(ifBlock); | |
1670 | if (!singleStatement) | |
1671 | return false; | |
1672 | ||
1673 | if (singleStatement->isBreak()) { | |
1674 | BreakNode* breakNode = static_cast<BreakNode*>(singleStatement); | |
1675 | Label* target = breakNode->trivialTarget(generator); | |
1676 | if (!target) | |
1677 | return false; | |
1678 | trueTarget = target; | |
1679 | fallThroughMode = FallThroughMeansFalse; | |
1680 | return true; | |
f9bf01c6 A |
1681 | } |
1682 | ||
93a37866 A |
1683 | if (singleStatement->isContinue()) { |
1684 | ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement); | |
1685 | Label* target = continueNode->trivialTarget(generator); | |
1686 | if (!target) | |
1687 | return false; | |
1688 | trueTarget = target; | |
1689 | fallThroughMode = FallThroughMeansFalse; | |
1690 | return true; | |
1691 | } | |
f9bf01c6 | 1692 | |
93a37866 | 1693 | return false; |
f9bf01c6 A |
1694 | } |
1695 | ||
93a37866 | 1696 | void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1697 | { |
81345200 | 1698 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 1699 | |
93a37866 | 1700 | RefPtr<Label> beforeThen = generator.newLabel(); |
f9bf01c6 A |
1701 | RefPtr<Label> beforeElse = generator.newLabel(); |
1702 | RefPtr<Label> afterElse = generator.newLabel(); | |
1703 | ||
93a37866 A |
1704 | Label* trueTarget = beforeThen.get(); |
1705 | Label* falseTarget = beforeElse.get(); | |
1706 | FallThroughMode fallThroughMode = FallThroughMeansTrue; | |
1707 | bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode); | |
f9bf01c6 | 1708 | |
93a37866 A |
1709 | generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode); |
1710 | generator.emitLabel(beforeThen.get()); | |
1711 | ||
1712 | if (!didFoldIfBlock) { | |
1713 | generator.emitNode(dst, m_ifBlock); | |
1714 | if (m_elseBlock) | |
1715 | generator.emitJump(afterElse.get()); | |
1716 | } | |
f9bf01c6 A |
1717 | |
1718 | generator.emitLabel(beforeElse.get()); | |
1719 | ||
93a37866 A |
1720 | if (m_elseBlock) |
1721 | generator.emitNode(dst, m_elseBlock); | |
f9bf01c6 A |
1722 | |
1723 | generator.emitLabel(afterElse.get()); | |
f9bf01c6 A |
1724 | } |
1725 | ||
1726 | // ------------------------------ DoWhileNode ---------------------------------- | |
1727 | ||
93a37866 | 1728 | void DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1729 | { |
93a37866 | 1730 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
f9bf01c6 A |
1731 | |
1732 | RefPtr<Label> topOfLoop = generator.newLabel(); | |
1733 | generator.emitLabel(topOfLoop.get()); | |
6fe7ccc8 | 1734 | generator.emitLoopHint(); |
81345200 | 1735 | generator.emitDebugHook(WillExecuteStatement, lastLine(), startOffset(), lineStartOffset()); |
93a37866 A |
1736 | |
1737 | generator.emitNode(dst, m_statement); | |
f9bf01c6 A |
1738 | |
1739 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 1740 | generator.emitDebugHook(WillExecuteStatement, lastLine(), startOffset(), lineStartOffset()); |
93a37866 | 1741 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
f9bf01c6 A |
1742 | |
1743 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
1744 | } |
1745 | ||
1746 | // ------------------------------ WhileNode ------------------------------------ | |
1747 | ||
93a37866 | 1748 | void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1749 | { |
93a37866 A |
1750 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
1751 | RefPtr<Label> topOfLoop = generator.newLabel(); | |
f9bf01c6 | 1752 | |
81345200 | 1753 | generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->startOffset(), m_expr->lineStartOffset()); |
93a37866 | 1754 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); |
f9bf01c6 | 1755 | |
f9bf01c6 | 1756 | generator.emitLabel(topOfLoop.get()); |
6fe7ccc8 | 1757 | generator.emitLoopHint(); |
f9bf01c6 A |
1758 | |
1759 | generator.emitNode(dst, m_statement); | |
1760 | ||
1761 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 1762 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 1763 | |
93a37866 | 1764 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
f9bf01c6 A |
1765 | |
1766 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
1767 | } |
1768 | ||
1769 | // ------------------------------ ForNode -------------------------------------- | |
1770 | ||
93a37866 | 1771 | void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1772 | { |
93a37866 | 1773 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
f9bf01c6 | 1774 | |
81345200 | 1775 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
1776 | |
1777 | if (m_expr1) | |
1778 | generator.emitNode(generator.ignoredResult(), m_expr1); | |
93a37866 | 1779 | |
f9bf01c6 | 1780 | RefPtr<Label> topOfLoop = generator.newLabel(); |
93a37866 A |
1781 | if (m_expr2) |
1782 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); | |
1783 | ||
f9bf01c6 | 1784 | generator.emitLabel(topOfLoop.get()); |
6fe7ccc8 | 1785 | generator.emitLoopHint(); |
f9bf01c6 | 1786 | |
93a37866 | 1787 | generator.emitNode(dst, m_statement); |
f9bf01c6 A |
1788 | |
1789 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 1790 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
1791 | if (m_expr3) |
1792 | generator.emitNode(generator.ignoredResult(), m_expr3); | |
1793 | ||
93a37866 A |
1794 | if (m_expr2) |
1795 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); | |
1796 | else | |
f9bf01c6 A |
1797 | generator.emitJump(topOfLoop.get()); |
1798 | ||
1799 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
1800 | } |
1801 | ||
1802 | // ------------------------------ ForInNode ------------------------------------ | |
1803 | ||
93a37866 | 1804 | void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1805 | { |
93a37866 | 1806 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
f9bf01c6 | 1807 | |
81345200 | 1808 | if (!m_lexpr->isAssignmentLocation()) { |
93a37866 A |
1809 | emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); |
1810 | return; | |
1811 | } | |
f9bf01c6 | 1812 | |
81345200 | 1813 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
1814 | |
1815 | RefPtr<RegisterID> base = generator.newTemporary(); | |
1816 | generator.emitNode(base.get(), m_expr); | |
1817 | RefPtr<RegisterID> i = generator.newTemporary(); | |
1818 | RefPtr<RegisterID> size = generator.newTemporary(); | |
1819 | RefPtr<RegisterID> expectedSubscript; | |
1820 | RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget()); | |
1821 | generator.emitJump(scope->continueTarget()); | |
1822 | ||
1823 | RefPtr<Label> loopStart = generator.newLabel(); | |
1824 | generator.emitLabel(loopStart.get()); | |
6fe7ccc8 | 1825 | generator.emitLoopHint(); |
f9bf01c6 A |
1826 | |
1827 | RegisterID* propertyName; | |
1828 | bool optimizedForinAccess = false; | |
1829 | if (m_lexpr->isResolveNode()) { | |
1830 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); | |
81345200 A |
1831 | Local local = generator.local(ident); |
1832 | if (!local.get()) { | |
f9bf01c6 A |
1833 | propertyName = generator.newTemporary(); |
1834 | RefPtr<RegisterID> protect = propertyName; | |
81345200 A |
1835 | if (generator.isStrictMode()) |
1836 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1837 | RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident); | |
1838 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1839 | generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); | |
f9bf01c6 | 1840 | } else { |
81345200 A |
1841 | expectedSubscript = generator.newTemporary(); |
1842 | propertyName = expectedSubscript.get(); | |
1843 | generator.emitMove(local.get(), propertyName); | |
1844 | generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), local.get()); | |
f9bf01c6 A |
1845 | optimizedForinAccess = true; |
1846 | } | |
1847 | } else if (m_lexpr->isDotAccessorNode()) { | |
1848 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); | |
1849 | const Identifier& ident = assignNode->identifier(); | |
1850 | propertyName = generator.newTemporary(); | |
1851 | RefPtr<RegisterID> protect = propertyName; | |
1852 | RegisterID* base = generator.emitNode(assignNode->base()); | |
1853 | ||
81345200 | 1854 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
f9bf01c6 | 1855 | generator.emitPutById(base, ident, propertyName); |
81345200 | 1856 | } else if (m_lexpr->isBracketAccessorNode()) { |
f9bf01c6 A |
1857 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); |
1858 | propertyName = generator.newTemporary(); | |
1859 | RefPtr<RegisterID> protect = propertyName; | |
1860 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); | |
1861 | RegisterID* subscript = generator.emitNode(assignNode->subscript()); | |
1862 | ||
81345200 | 1863 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
f9bf01c6 | 1864 | generator.emitPutByVal(base.get(), subscript, propertyName); |
81345200 A |
1865 | } else { |
1866 | ASSERT(m_lexpr->isDeconstructionNode()); | |
1867 | DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr); | |
1868 | auto binding = assignNode->bindings(); | |
1869 | if (binding->isBindingNode()) { | |
1870 | auto simpleBinding = static_cast<BindingNode*>(binding); | |
1871 | Identifier ident = simpleBinding->boundProperty(); | |
1872 | Local local = generator.local(ident); | |
1873 | propertyName = local.get(); | |
1874 | if (!propertyName || local.isCaptured()) | |
1875 | goto genericBinding; | |
1876 | expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); | |
1877 | generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName); | |
1878 | optimizedForinAccess = true; | |
1879 | goto completedSimpleBinding; | |
1880 | } else { | |
1881 | genericBinding: | |
1882 | propertyName = generator.newTemporary(); | |
1883 | RefPtr<RegisterID> protect(propertyName); | |
1884 | assignNode->bindings()->bindValue(generator, propertyName); | |
1885 | } | |
1886 | completedSimpleBinding: | |
1887 | ; | |
1888 | } | |
f9bf01c6 A |
1889 | |
1890 | generator.emitNode(dst, m_statement); | |
1891 | ||
1892 | if (optimizedForinAccess) | |
1893 | generator.popOptimisedForIn(); | |
1894 | ||
1895 | generator.emitLabel(scope->continueTarget()); | |
1896 | generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); | |
81345200 | 1897 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 1898 | generator.emitLabel(scope->breakTarget()); |
f9bf01c6 A |
1899 | } |
1900 | ||
81345200 A |
1901 | // ------------------------------ ForOfNode ------------------------------------ |
1902 | void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1903 | { | |
1904 | if (!m_lexpr->isAssignmentLocation()) { | |
1905 | emitThrowReferenceError(generator, "Left side of for-of statement is not a reference."); | |
1906 | return; | |
1907 | } | |
1908 | ||
1909 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); | |
1910 | ||
1911 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); | |
1912 | auto extractor = [this, dst](BytecodeGenerator& generator, RegisterID* value) | |
1913 | { | |
1914 | if (m_lexpr->isResolveNode()) { | |
1915 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); | |
1916 | if (Local local = generator.local(ident)) | |
1917 | generator.emitMove(local.get(), value); | |
1918 | else { | |
1919 | if (generator.isStrictMode()) | |
1920 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1921 | RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident); | |
1922 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
1923 | generator.emitPutToScope(scope, ident, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); | |
1924 | } | |
1925 | } else if (m_lexpr->isDotAccessorNode()) { | |
1926 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); | |
1927 | const Identifier& ident = assignNode->identifier(); | |
1928 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); | |
1929 | ||
1930 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); | |
1931 | generator.emitPutById(base.get(), ident, value); | |
1932 | } else if (m_lexpr->isBracketAccessorNode()) { | |
1933 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); | |
1934 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); | |
1935 | RegisterID* subscript = generator.emitNode(assignNode->subscript()); | |
1936 | ||
1937 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); | |
1938 | generator.emitPutByVal(base.get(), subscript, value); | |
1939 | } else { | |
1940 | ASSERT(m_lexpr->isDeconstructionNode()); | |
1941 | DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr); | |
1942 | assignNode->bindings()->bindValue(generator, value); | |
1943 | } | |
1944 | generator.emitNode(dst, m_statement); | |
1945 | }; | |
1946 | generator.emitEnumeration(this, m_expr, extractor); | |
1947 | } | |
1948 | ||
f9bf01c6 A |
1949 | // ------------------------------ ContinueNode --------------------------------- |
1950 | ||
93a37866 A |
1951 | Label* ContinueNode::trivialTarget(BytecodeGenerator& generator) |
1952 | { | |
1953 | if (generator.shouldEmitDebugHooks()) | |
1954 | return 0; | |
1955 | ||
81345200 | 1956 | LabelScopePtr scope = generator.continueTarget(m_ident); |
93a37866 A |
1957 | ASSERT(scope); |
1958 | ||
1959 | if (generator.scopeDepth() != scope->scopeDepth()) | |
1960 | return 0; | |
1961 | ||
1962 | return scope->continueTarget(); | |
1963 | } | |
1964 | ||
1965 | void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
f9bf01c6 | 1966 | { |
81345200 | 1967 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 1968 | |
81345200 | 1969 | LabelScopePtr scope = generator.continueTarget(m_ident); |
14957cd0 | 1970 | ASSERT(scope); |
f9bf01c6 | 1971 | |
93a37866 A |
1972 | generator.emitPopScopes(scope->scopeDepth()); |
1973 | generator.emitJump(scope->continueTarget()); | |
f9bf01c6 A |
1974 | } |
1975 | ||
1976 | // ------------------------------ BreakNode ------------------------------------ | |
1977 | ||
93a37866 | 1978 | Label* BreakNode::trivialTarget(BytecodeGenerator& generator) |
f9bf01c6 | 1979 | { |
93a37866 A |
1980 | if (generator.shouldEmitDebugHooks()) |
1981 | return 0; | |
1982 | ||
81345200 | 1983 | LabelScopePtr scope = generator.breakTarget(m_ident); |
93a37866 A |
1984 | ASSERT(scope); |
1985 | ||
1986 | if (generator.scopeDepth() != scope->scopeDepth()) | |
1987 | return 0; | |
1988 | ||
1989 | return scope->breakTarget(); | |
1990 | } | |
1991 | ||
1992 | void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
1993 | { | |
81345200 | 1994 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 1995 | |
81345200 | 1996 | LabelScopePtr scope = generator.breakTarget(m_ident); |
14957cd0 | 1997 | ASSERT(scope); |
f9bf01c6 | 1998 | |
93a37866 A |
1999 | generator.emitPopScopes(scope->scopeDepth()); |
2000 | generator.emitJump(scope->breakTarget()); | |
f9bf01c6 A |
2001 | } |
2002 | ||
2003 | // ------------------------------ ReturnNode ----------------------------------- | |
2004 | ||
93a37866 | 2005 | void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2006 | { |
81345200 | 2007 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
14957cd0 | 2008 | ASSERT(generator.codeType() == FunctionCode); |
f9bf01c6 A |
2009 | |
2010 | if (dst == generator.ignoredResult()) | |
2011 | dst = 0; | |
93a37866 A |
2012 | |
2013 | RefPtr<RegisterID> returnRegister = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); | |
f9bf01c6 | 2014 | if (generator.scopeDepth()) { |
93a37866 A |
2015 | returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get()); |
2016 | generator.emitPopScopes(0); | |
f9bf01c6 | 2017 | } |
93a37866 | 2018 | |
81345200 | 2019 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); |
93a37866 | 2020 | generator.emitReturn(returnRegister.get()); |
f9bf01c6 A |
2021 | } |
2022 | ||
2023 | // ------------------------------ WithNode ------------------------------------- | |
2024 | ||
93a37866 | 2025 | void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2026 | { |
81345200 | 2027 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 A |
2028 | |
2029 | RefPtr<RegisterID> scope = generator.emitNode(m_expr); | |
81345200 | 2030 | generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot); |
93a37866 A |
2031 | generator.emitPushWithScope(scope.get()); |
2032 | generator.emitNode(dst, m_statement); | |
f9bf01c6 | 2033 | generator.emitPopScope(); |
f9bf01c6 A |
2034 | } |
2035 | ||
2036 | // ------------------------------ CaseClauseNode -------------------------------- | |
2037 | ||
2038 | inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2039 | { | |
93a37866 A |
2040 | if (!m_statements) |
2041 | return; | |
2042 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
2043 | } |
2044 | ||
2045 | // ------------------------------ CaseBlockNode -------------------------------- | |
2046 | ||
2047 | enum SwitchKind { | |
2048 | SwitchUnset = 0, | |
2049 | SwitchNumber = 1, | |
2050 | SwitchString = 2, | |
2051 | SwitchNeither = 3 | |
2052 | }; | |
2053 | ||
2054 | static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) | |
2055 | { | |
2056 | for (; list; list = list->getNext()) { | |
2057 | ExpressionNode* clauseExpression = list->getClause()->expr(); | |
2058 | literalVector.append(clauseExpression); | |
2059 | if (clauseExpression->isNumber()) { | |
2060 | double value = static_cast<NumberNode*>(clauseExpression)->value(); | |
2061 | int32_t intVal = static_cast<int32_t>(value); | |
2062 | if ((typeForTable & ~SwitchNumber) || (intVal != value)) { | |
2063 | typeForTable = SwitchNeither; | |
2064 | break; | |
2065 | } | |
2066 | if (intVal < min_num) | |
2067 | min_num = intVal; | |
2068 | if (intVal > max_num) | |
2069 | max_num = intVal; | |
2070 | typeForTable = SwitchNumber; | |
2071 | continue; | |
2072 | } | |
2073 | if (clauseExpression->isString()) { | |
2074 | if (typeForTable & ~SwitchString) { | |
2075 | typeForTable = SwitchNeither; | |
2076 | break; | |
2077 | } | |
93a37866 | 2078 | const String& value = static_cast<StringNode*>(clauseExpression)->value().string(); |
14957cd0 | 2079 | if (singleCharacterSwitch &= value.length() == 1) { |
6fe7ccc8 | 2080 | int32_t intVal = value[0]; |
f9bf01c6 A |
2081 | if (intVal < min_num) |
2082 | min_num = intVal; | |
2083 | if (intVal > max_num) | |
2084 | max_num = intVal; | |
2085 | } | |
2086 | typeForTable = SwitchString; | |
2087 | continue; | |
2088 | } | |
2089 | typeForTable = SwitchNeither; | |
2090 | break; | |
2091 | } | |
2092 | } | |
93a37866 A |
2093 | |
2094 | static inline size_t length(ClauseListNode* list1, ClauseListNode* list2) | |
f9bf01c6 | 2095 | { |
93a37866 A |
2096 | size_t length = 0; |
2097 | for (ClauseListNode* node = list1; node; node = node->getNext()) | |
2098 | ++length; | |
2099 | for (ClauseListNode* node = list2; node; node = node->getNext()) | |
2100 | ++length; | |
2101 | return length; | |
2102 | } | |
2103 | ||
2104 | SwitchInfo::SwitchType CaseBlockNode::tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) | |
2105 | { | |
2106 | if (length(m_list1, m_list2) < s_tableSwitchMinimum) | |
2107 | return SwitchInfo::SwitchNone; | |
2108 | ||
f9bf01c6 A |
2109 | SwitchKind typeForTable = SwitchUnset; |
2110 | bool singleCharacterSwitch = true; | |
2111 | ||
2112 | processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); | |
2113 | processClauseList(m_list2, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); | |
2114 | ||
2115 | if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) | |
2116 | return SwitchInfo::SwitchNone; | |
2117 | ||
2118 | if (typeForTable == SwitchNumber) { | |
2119 | int32_t range = max_num - min_num; | |
2120 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) | |
2121 | return SwitchInfo::SwitchImmediate; | |
2122 | return SwitchInfo::SwitchNone; | |
2123 | } | |
2124 | ||
2125 | ASSERT(typeForTable == SwitchString); | |
2126 | ||
2127 | if (singleCharacterSwitch) { | |
2128 | int32_t range = max_num - min_num; | |
2129 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) | |
2130 | return SwitchInfo::SwitchCharacter; | |
2131 | } | |
2132 | ||
2133 | return SwitchInfo::SwitchString; | |
2134 | } | |
2135 | ||
93a37866 | 2136 | void CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) |
f9bf01c6 A |
2137 | { |
2138 | RefPtr<Label> defaultLabel; | |
2139 | Vector<RefPtr<Label>, 8> labelVector; | |
2140 | Vector<ExpressionNode*, 8> literalVector; | |
2141 | int32_t min_num = std::numeric_limits<int32_t>::max(); | |
2142 | int32_t max_num = std::numeric_limits<int32_t>::min(); | |
93a37866 | 2143 | SwitchInfo::SwitchType switchType = tryTableSwitch(literalVector, min_num, max_num); |
f9bf01c6 A |
2144 | |
2145 | if (switchType != SwitchInfo::SwitchNone) { | |
2146 | // Prepare the various labels | |
2147 | for (uint32_t i = 0; i < literalVector.size(); i++) | |
2148 | labelVector.append(generator.newLabel()); | |
2149 | defaultLabel = generator.newLabel(); | |
2150 | generator.beginSwitch(switchExpression, switchType); | |
2151 | } else { | |
2152 | // Setup jumps | |
2153 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { | |
2154 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); | |
2155 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); | |
2156 | generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); | |
2157 | labelVector.append(generator.newLabel()); | |
2158 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); | |
2159 | } | |
2160 | ||
2161 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { | |
2162 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); | |
2163 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); | |
2164 | generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); | |
2165 | labelVector.append(generator.newLabel()); | |
2166 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); | |
2167 | } | |
2168 | defaultLabel = generator.newLabel(); | |
2169 | generator.emitJump(defaultLabel.get()); | |
2170 | } | |
2171 | ||
f9bf01c6 A |
2172 | size_t i = 0; |
2173 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { | |
2174 | generator.emitLabel(labelVector[i++].get()); | |
2175 | list->getClause()->emitBytecode(generator, dst); | |
2176 | } | |
2177 | ||
2178 | if (m_defaultClause) { | |
2179 | generator.emitLabel(defaultLabel.get()); | |
2180 | m_defaultClause->emitBytecode(generator, dst); | |
2181 | } | |
2182 | ||
2183 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { | |
2184 | generator.emitLabel(labelVector[i++].get()); | |
2185 | list->getClause()->emitBytecode(generator, dst); | |
2186 | } | |
2187 | if (!m_defaultClause) | |
2188 | generator.emitLabel(defaultLabel.get()); | |
2189 | ||
2190 | ASSERT(i == labelVector.size()); | |
2191 | if (switchType != SwitchInfo::SwitchNone) { | |
2192 | ASSERT(labelVector.size() == literalVector.size()); | |
2193 | generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); | |
2194 | } | |
f9bf01c6 A |
2195 | } |
2196 | ||
2197 | // ------------------------------ SwitchNode ----------------------------------- | |
2198 | ||
93a37866 | 2199 | void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2200 | { |
81345200 | 2201 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2202 | |
93a37866 | 2203 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Switch); |
f9bf01c6 A |
2204 | |
2205 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); | |
93a37866 | 2206 | m_block->emitBytecodeForBlock(generator, r0.get(), dst); |
f9bf01c6 A |
2207 | |
2208 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
2209 | } |
2210 | ||
2211 | // ------------------------------ LabelNode ------------------------------------ | |
2212 | ||
93a37866 | 2213 | void LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2214 | { |
81345200 | 2215 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2216 | |
14957cd0 | 2217 | ASSERT(!generator.breakTarget(m_name)); |
f9bf01c6 | 2218 | |
93a37866 A |
2219 | LabelScopePtr scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); |
2220 | generator.emitNode(dst, m_statement); | |
f9bf01c6 A |
2221 | |
2222 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
2223 | } |
2224 | ||
2225 | // ------------------------------ ThrowNode ------------------------------------ | |
2226 | ||
93a37866 | 2227 | void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2228 | { |
81345200 | 2229 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2230 | |
2231 | if (dst == generator.ignoredResult()) | |
2232 | dst = 0; | |
2233 | RefPtr<RegisterID> expr = generator.emitNode(m_expr); | |
81345200 | 2234 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 2235 | generator.emitThrow(expr.get()); |
f9bf01c6 A |
2236 | } |
2237 | ||
2238 | // ------------------------------ TryNode -------------------------------------- | |
2239 | ||
93a37866 | 2240 | void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
2241 | { |
2242 | // NOTE: The catch and finally blocks must be labeled explicitly, so the | |
2243 | // optimizer knows they may be jumped to from anywhere. | |
2244 | ||
81345200 | 2245 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 A |
2246 | |
2247 | ASSERT(m_catchBlock || m_finallyBlock); | |
f9bf01c6 A |
2248 | |
2249 | RefPtr<Label> tryStartLabel = generator.newLabel(); | |
93a37866 A |
2250 | generator.emitLabel(tryStartLabel.get()); |
2251 | ||
6fe7ccc8 A |
2252 | if (m_finallyBlock) |
2253 | generator.pushFinallyContext(m_finallyBlock); | |
93a37866 | 2254 | TryData* tryData = generator.pushTry(tryStartLabel.get()); |
f9bf01c6 | 2255 | |
f9bf01c6 A |
2256 | generator.emitNode(dst, m_tryBlock); |
2257 | ||
2258 | if (m_catchBlock) { | |
2259 | RefPtr<Label> catchEndLabel = generator.newLabel(); | |
2260 | ||
2261 | // Normal path: jump over the catch block. | |
2262 | generator.emitJump(catchEndLabel.get()); | |
2263 | ||
2264 | // Uncaught exception path: the catch block. | |
2265 | RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); | |
93a37866 A |
2266 | RefPtr<RegisterID> exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get()); |
2267 | ||
2268 | if (m_finallyBlock) { | |
2269 | // If the catch block throws an exception and we have a finally block, then the finally | |
2270 | // block should "catch" that exception. | |
2271 | tryData = generator.pushTry(here.get()); | |
2272 | } | |
2273 | ||
81345200 | 2274 | generator.emitPushCatchScope(m_exceptionIdent, exceptionRegister.get(), DontDelete); |
f9bf01c6 A |
2275 | generator.emitNode(dst, m_catchBlock); |
2276 | generator.emitPopScope(); | |
2277 | generator.emitLabel(catchEndLabel.get()); | |
2278 | } | |
2279 | ||
2280 | if (m_finallyBlock) { | |
93a37866 A |
2281 | RefPtr<Label> preFinallyLabel = generator.emitLabel(generator.newLabel().get()); |
2282 | ||
f9bf01c6 | 2283 | generator.popFinallyContext(); |
6fe7ccc8 | 2284 | |
f9bf01c6 A |
2285 | RefPtr<Label> finallyEndLabel = generator.newLabel(); |
2286 | ||
6fe7ccc8 A |
2287 | // Normal path: run the finally code, and jump to the end. |
2288 | generator.emitNode(dst, m_finallyBlock); | |
f9bf01c6 A |
2289 | generator.emitJump(finallyEndLabel.get()); |
2290 | ||
2291 | // Uncaught exception path: invoke the finally block, then re-throw the exception. | |
93a37866 | 2292 | RefPtr<RegisterID> tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get()); |
f9bf01c6 | 2293 | generator.emitNode(dst, m_finallyBlock); |
6fe7ccc8 | 2294 | generator.emitThrow(tempExceptionRegister.get()); |
f9bf01c6 A |
2295 | |
2296 | generator.emitLabel(finallyEndLabel.get()); | |
2297 | } | |
f9bf01c6 A |
2298 | } |
2299 | ||
2300 | // ------------------------------ ScopeNode ----------------------------- | |
2301 | ||
2302 | inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2303 | { | |
93a37866 A |
2304 | if (!m_statements) |
2305 | return; | |
2306 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
2307 | } |
2308 | ||
2309 | // ------------------------------ ProgramNode ----------------------------- | |
2310 | ||
93a37866 | 2311 | void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2312 | { |
81345200 | 2313 | generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 A |
2314 | |
2315 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); | |
2316 | generator.emitLoad(dstRegister.get(), jsUndefined()); | |
2317 | emitStatementsBytecode(generator, dstRegister.get()); | |
2318 | ||
81345200 | 2319 | generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2320 | generator.emitEnd(dstRegister.get()); |
f9bf01c6 A |
2321 | } |
2322 | ||
2323 | // ------------------------------ EvalNode ----------------------------- | |
2324 | ||
93a37866 | 2325 | void EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2326 | { |
81345200 | 2327 | generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 A |
2328 | |
2329 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); | |
2330 | generator.emitLoad(dstRegister.get(), jsUndefined()); | |
2331 | emitStatementsBytecode(generator, dstRegister.get()); | |
2332 | ||
81345200 | 2333 | generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2334 | generator.emitEnd(dstRegister.get()); |
f9bf01c6 A |
2335 | } |
2336 | ||
2337 | // ------------------------------ FunctionBodyNode ----------------------------- | |
2338 | ||
93a37866 | 2339 | void FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2340 | { |
81345200 | 2341 | generator.emitDebugHook(DidEnterCallFrame, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 | 2342 | emitStatementsBytecode(generator, generator.ignoredResult()); |
14957cd0 | 2343 | |
f9bf01c6 | 2344 | StatementNode* singleStatement = this->singleStatement(); |
14957cd0 A |
2345 | ReturnNode* returnNode = 0; |
2346 | ||
2347 | // Check for a return statement at the end of a function composed of a single block. | |
f9bf01c6 A |
2348 | if (singleStatement && singleStatement->isBlock()) { |
2349 | StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); | |
2350 | if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) | |
14957cd0 A |
2351 | returnNode = static_cast<ReturnNode*>(lastStatementInBlock); |
2352 | } | |
2353 | ||
2354 | // If there is no return we must automatically insert one. | |
2355 | if (!returnNode) { | |
2356 | RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); | |
81345200 A |
2357 | ASSERT(startOffset() >= lineStartOffset()); |
2358 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); | |
14957cd0 | 2359 | generator.emitReturn(r0); |
93a37866 | 2360 | return; |
14957cd0 A |
2361 | } |
2362 | ||
2363 | // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare. | |
2364 | if (static_cast<BlockNode*>(singleStatement)->singleStatement()) { | |
2365 | ExpressionNode* returnValueExpression = returnNode->value(); | |
2366 | if (returnValueExpression && returnValueExpression->isSubtract()) { | |
2367 | ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs(); | |
2368 | ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs(); | |
6fe7ccc8 A |
2369 | if (lhsExpression->isResolveNode() |
2370 | && rhsExpression->isResolveNode() | |
2371 | && generator.isArgumentNumber(static_cast<ResolveNode*>(lhsExpression)->identifier(), 0) | |
2372 | && generator.isArgumentNumber(static_cast<ResolveNode*>(rhsExpression)->identifier(), 1)) { | |
2373 | ||
2374 | generator.setIsNumericCompareFunction(true); | |
14957cd0 A |
2375 | } |
2376 | } | |
f9bf01c6 | 2377 | } |
f9bf01c6 A |
2378 | } |
2379 | ||
2380 | // ------------------------------ FuncDeclNode --------------------------------- | |
2381 | ||
93a37866 | 2382 | void FuncDeclNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
f9bf01c6 | 2383 | { |
f9bf01c6 A |
2384 | } |
2385 | ||
2386 | // ------------------------------ FuncExprNode --------------------------------- | |
2387 | ||
2388 | RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2389 | { | |
2390 | return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); | |
2391 | } | |
81345200 A |
2392 | |
2393 | // ------------------------------ DeconstructingAssignmentNode ----------------- | |
2394 | RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2395 | { | |
2396 | if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer)) | |
2397 | return result; | |
2398 | RefPtr<RegisterID> initializer = generator.tempDestination(dst); | |
2399 | generator.emitNode(initializer.get(), m_initializer); | |
2400 | m_bindings->bindValue(generator, initializer.get()); | |
2401 | return generator.moveToDestinationIfNeeded(dst, initializer.get()); | |
2402 | } | |
2403 | ||
2404 | DeconstructionPatternNode::~DeconstructionPatternNode() | |
2405 | { | |
2406 | } | |
2407 | ||
2408 | void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const | |
2409 | { | |
2410 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2411 | auto target = m_targetPatterns[i]; | |
2412 | if (!target) | |
2413 | continue; | |
2414 | RefPtr<RegisterID> temp = generator.newTemporary(); | |
2415 | generator.emitLoad(temp.get(), jsNumber(i)); | |
2416 | generator.emitGetByVal(temp.get(), rhs, temp.get()); | |
2417 | target->bindValue(generator, temp.get()); | |
2418 | } | |
2419 | } | |
2420 | ||
2421 | RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs) | |
2422 | { | |
2423 | if (rhs->isResolveNode() | |
2424 | && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier()) | |
2425 | && !generator.symbolTable().slowArguments()) { | |
2426 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2427 | auto target = m_targetPatterns[i]; | |
2428 | if (!target) | |
2429 | continue; | |
2430 | ||
2431 | RefPtr<RegisterID> temp = generator.newTemporary(); | |
2432 | generator.emitLoad(temp.get(), jsNumber(i)); | |
2433 | generator.emitGetArgumentByVal(temp.get(), generator.uncheckedRegisterForArguments(), temp.get()); | |
2434 | target->bindValue(generator, temp.get()); | |
2435 | } | |
2436 | if (dst == generator.ignoredResult() || !dst) | |
2437 | return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); | |
2438 | Local local = generator.local(generator.vm()->propertyNames->arguments); | |
2439 | return generator.moveToDestinationIfNeeded(dst, local.get()); | |
2440 | } | |
2441 | if (!rhs->isSimpleArray()) | |
2442 | return 0; | |
2443 | ||
2444 | RefPtr<RegisterID> resultRegister; | |
2445 | if (dst && dst != generator.ignoredResult()) | |
2446 | resultRegister = generator.emitNewArray(generator.newTemporary(), 0, 0); | |
2447 | ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements(); | |
2448 | Vector<ExpressionNode*> elements; | |
2449 | for (; elementNodes; elementNodes = elementNodes->next()) | |
2450 | elements.append(elementNodes->value()); | |
2451 | if (m_targetPatterns.size() != elements.size()) | |
2452 | return 0; | |
2453 | Vector<RefPtr<RegisterID>> registers; | |
2454 | registers.reserveCapacity(m_targetPatterns.size()); | |
2455 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2456 | registers.uncheckedAppend(generator.newTemporary()); | |
2457 | generator.emitNode(registers.last().get(), elements[i]); | |
2458 | if (resultRegister) | |
2459 | generator.emitPutByIndex(resultRegister.get(), i, registers.last().get()); | |
2460 | } | |
2461 | ||
2462 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2463 | if (m_targetPatterns[i]) | |
2464 | m_targetPatterns[i]->bindValue(generator, registers[i].get()); | |
2465 | } | |
2466 | if (resultRegister) | |
2467 | return generator.moveToDestinationIfNeeded(dst, resultRegister.get()); | |
2468 | return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); | |
2469 | } | |
2470 | ||
2471 | void ArrayPatternNode::toString(StringBuilder& builder) const | |
2472 | { | |
2473 | builder.append('['); | |
2474 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2475 | if (!m_targetPatterns[i]) { | |
2476 | builder.append(','); | |
2477 | continue; | |
2478 | } | |
2479 | m_targetPatterns[i]->toString(builder); | |
2480 | if (i < m_targetPatterns.size() - 1) | |
2481 | builder.append(','); | |
2482 | } | |
2483 | builder.append(']'); | |
2484 | } | |
2485 | ||
2486 | void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
2487 | { | |
2488 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2489 | if (DeconstructionPatternNode* node = m_targetPatterns[i].get()) | |
2490 | node->collectBoundIdentifiers(identifiers); | |
2491 | } | |
2492 | } | |
2493 | ||
2494 | void ObjectPatternNode::toString(StringBuilder& builder) const | |
2495 | { | |
2496 | builder.append('{'); | |
2497 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2498 | if (m_targetPatterns[i].wasString) { | |
2499 | builder.append('"'); | |
2500 | escapeStringToBuilder(builder, m_targetPatterns[i].propertyName.string()); | |
2501 | builder.append('"'); | |
2502 | } else | |
2503 | builder.append(m_targetPatterns[i].propertyName.string()); | |
2504 | builder.append(":"); | |
2505 | m_targetPatterns[i].pattern->toString(builder); | |
2506 | if (i < m_targetPatterns.size() - 1) | |
2507 | builder.append(','); | |
2508 | } | |
2509 | builder.append('}'); | |
2510 | } | |
2511 | ||
2512 | void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const | |
2513 | { | |
2514 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
2515 | auto& target = m_targetPatterns[i]; | |
2516 | RefPtr<RegisterID> temp = generator.newTemporary(); | |
2517 | generator.emitGetById(temp.get(), rhs, target.propertyName); | |
2518 | target.pattern->bindValue(generator, temp.get()); | |
2519 | } | |
2520 | } | |
2521 | ||
2522 | void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
2523 | { | |
2524 | for (size_t i = 0; i < m_targetPatterns.size(); i++) | |
2525 | m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers); | |
2526 | } | |
2527 | ||
2528 | void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const | |
2529 | { | |
2530 | if (Local local = generator.local(m_boundProperty)) { | |
2531 | if (local.isReadOnly()) { | |
2532 | generator.emitReadOnlyExceptionIfNeeded(); | |
2533 | return; | |
2534 | } | |
2535 | generator.emitMove(local.get(), value); | |
2536 | return; | |
2537 | } | |
2538 | if (generator.isStrictMode()) | |
2539 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); | |
2540 | RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty); | |
2541 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); | |
2542 | generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); | |
2543 | return; | |
2544 | } | |
2545 | ||
2546 | void BindingNode::toString(StringBuilder& builder) const | |
2547 | { | |
2548 | builder.append(m_boundProperty.string()); | |
2549 | } | |
2550 | ||
2551 | void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
2552 | { | |
2553 | identifiers.append(m_boundProperty); | |
2554 | } | |
2555 | ||
2556 | RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*) | |
2557 | { | |
2558 | RELEASE_ASSERT_NOT_REACHED(); | |
2559 | return 0; | |
2560 | } | |
f9bf01c6 A |
2561 | |
2562 | } // namespace JSC |