]>
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) | |
ed1e77d3 | 4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2015 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" |
ed1e77d3 | 43 | #include "JSTemplateRegistryKey.h" |
f9bf01c6 A |
44 | #include "Parser.h" |
45 | #include "PropertyNameArray.h" | |
4e4e5a6f | 46 | #include "RegExpCache.h" |
f9bf01c6 A |
47 | #include "RegExpObject.h" |
48 | #include "SamplingTool.h" | |
81345200 | 49 | #include "StackAlignment.h" |
ed1e77d3 | 50 | #include "TemplateRegistryKey.h" |
f9bf01c6 A |
51 | #include <wtf/Assertions.h> |
52 | #include <wtf/RefCountedLeakCounter.h> | |
53 | #include <wtf/Threading.h> | |
54 | ||
55 | using namespace WTF; | |
56 | ||
57 | namespace JSC { | |
58 | ||
59 | /* | |
60 | Details of the emitBytecode function. | |
61 | ||
62 | Return value: The register holding the production's value. | |
63 | dst: An optional parameter specifying the most efficient destination at | |
64 | which to store the production's value. The callee must honor dst. | |
65 | ||
66 | The dst argument provides for a crude form of copy propagation. For example, | |
67 | ||
68 | x = 1 | |
69 | ||
70 | becomes | |
71 | ||
72 | load r[x], 1 | |
73 | ||
74 | instead of | |
75 | ||
76 | load r0, 1 | |
77 | mov r[x], r0 | |
78 | ||
79 | because the assignment node, "x =", passes r[x] as dst to the number node, "1". | |
80 | */ | |
81 | ||
93a37866 A |
82 | void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
83 | { | |
84 | RegisterID* result = generator.emitNode(this); | |
85 | if (fallThroughMode == FallThroughMeansTrue) | |
86 | generator.emitJumpIfFalse(result, falseTarget); | |
87 | else | |
88 | generator.emitJumpIfTrue(result, trueTarget); | |
89 | } | |
90 | ||
f9bf01c6 A |
91 | // ------------------------------ ThrowableExpressionData -------------------------------- |
92 | ||
93a37866 | 93 | RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) |
f9bf01c6 | 94 | { |
81345200 | 95 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
14957cd0 A |
96 | generator.emitThrowReferenceError(message); |
97 | return generator.newTemporary(); | |
f9bf01c6 A |
98 | } |
99 | ||
93a37866 | 100 | // ------------------------------ ConstantNode ---------------------------------- |
f9bf01c6 | 101 | |
93a37866 | 102 | void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 103 | { |
93a37866 A |
104 | TriState value = jsValue(generator).pureToBoolean(); |
105 | if (value == MixedTriState) | |
106 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); | |
107 | else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) | |
108 | generator.emitJump(trueTarget); | |
109 | else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue) | |
110 | generator.emitJump(falseTarget); | |
f9bf01c6 | 111 | |
93a37866 | 112 | // All other cases are unconditional fall-throughs, like "if (true)". |
f9bf01c6 A |
113 | } |
114 | ||
93a37866 | 115 | RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
116 | { |
117 | if (dst == generator.ignoredResult()) | |
118 | return 0; | |
93a37866 | 119 | return generator.emitLoad(dst, jsValue(generator)); |
f9bf01c6 A |
120 | } |
121 | ||
93a37866 | 122 | JSValue StringNode::jsValue(BytecodeGenerator& generator) const |
f9bf01c6 | 123 | { |
93a37866 | 124 | return generator.addStringConstant(m_value); |
f9bf01c6 A |
125 | } |
126 | ||
ed1e77d3 A |
127 | // ------------------------------ NumberNode ---------------------------------- |
128 | ||
129 | RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
130 | { | |
131 | if (dst == generator.ignoredResult()) | |
132 | return nullptr; | |
133 | return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double); | |
134 | } | |
135 | ||
f9bf01c6 A |
136 | // ------------------------------ RegExpNode ----------------------------------- |
137 | ||
138 | RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
139 | { | |
f9bf01c6 A |
140 | if (dst == generator.ignoredResult()) |
141 | return 0; | |
93a37866 | 142 | return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); |
f9bf01c6 A |
143 | } |
144 | ||
145 | // ------------------------------ ThisNode ------------------------------------- | |
146 | ||
147 | RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
148 | { | |
ed1e77d3 A |
149 | if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived) |
150 | generator.emitTDZCheck(generator.thisRegister()); | |
151 | ||
f9bf01c6 A |
152 | if (dst == generator.ignoredResult()) |
153 | return 0; | |
ed1e77d3 A |
154 | |
155 | RegisterID* result = generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); | |
156 | if (generator.vm()->typeProfiler()) { | |
157 | generator.emitProfileType(generator.thisRegister(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
158 | static const unsigned thisLength = 4; | |
159 | generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + thisLength, -1)); | |
160 | } | |
161 | return result; | |
162 | } | |
163 | ||
164 | // ------------------------------ SuperNode ------------------------------------- | |
165 | ||
166 | RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
167 | { | |
168 | if (dst == generator.ignoredResult()) | |
169 | return 0; | |
170 | ||
171 | RegisterID callee; | |
172 | callee.setIndex(JSStack::Callee); | |
173 | ||
174 | RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); | |
175 | RefPtr<RegisterID> protoParent = generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); | |
176 | return generator.emitGetById(generator.finalDestination(dst), protoParent.get(), generator.propertyNames().constructor); | |
177 | } | |
178 | ||
179 | static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator) | |
180 | { | |
181 | RegisterID callee; | |
182 | callee.setIndex(JSStack::Callee); | |
183 | ||
184 | RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); | |
185 | return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); | |
f9bf01c6 A |
186 | } |
187 | ||
188 | // ------------------------------ ResolveNode ---------------------------------- | |
189 | ||
190 | bool ResolveNode::isPure(BytecodeGenerator& generator) const | |
191 | { | |
ed1e77d3 | 192 | return generator.variable(m_ident).offset().isStack(); |
f9bf01c6 A |
193 | } |
194 | ||
195 | RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
196 | { | |
ed1e77d3 A |
197 | Variable var = generator.variable(m_ident); |
198 | if (RegisterID* local = var.local()) { | |
f9bf01c6 | 199 | if (dst == generator.ignoredResult()) |
ed1e77d3 A |
200 | return nullptr; |
201 | if (generator.vm()->typeProfiler()) { | |
202 | generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); | |
203 | generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); | |
204 | } | |
205 | return generator.moveToDestinationIfNeeded(dst, local); | |
f9bf01c6 A |
206 | } |
207 | ||
81345200 A |
208 | JSTextPosition divot = m_start + m_ident.length(); |
209 | generator.emitExpressionInfo(divot, m_start, divot); | |
ed1e77d3 A |
210 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
211 | RegisterID* finalDest = generator.finalDestination(dst); | |
212 | RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), var, ThrowIfNotFound); | |
213 | if (generator.vm()->typeProfiler()) { | |
214 | generator.emitProfileType(finalDest, var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); | |
215 | generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); | |
216 | } | |
217 | return result; | |
218 | } | |
219 | ||
220 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) | |
221 | // ------------------------------ TemplateStringNode ----------------------------------- | |
222 | ||
223 | RegisterID* TemplateStringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
224 | { | |
225 | if (dst == generator.ignoredResult()) | |
226 | return nullptr; | |
227 | return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked()))); | |
228 | } | |
229 | ||
230 | // ------------------------------ TemplateLiteralNode ----------------------------------- | |
231 | ||
232 | RegisterID* TemplateLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
233 | { | |
234 | if (!m_templateExpressions) { | |
235 | TemplateStringNode* templateString = m_templateStrings->value(); | |
236 | ASSERT_WITH_MESSAGE(!m_templateStrings->next(), "Only one template element exists because there's no expression in a given template literal."); | |
237 | return generator.emitNode(dst, templateString); | |
238 | } | |
239 | ||
240 | Vector<RefPtr<RegisterID>, 16> temporaryRegisters; | |
241 | ||
242 | TemplateStringListNode* templateString = m_templateStrings; | |
243 | TemplateExpressionListNode* templateExpression = m_templateExpressions; | |
244 | for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) { | |
245 | // Evaluate TemplateString. | |
246 | if (!templateString->value()->cooked().isEmpty()) { | |
247 | temporaryRegisters.append(generator.newTemporary()); | |
248 | generator.emitNode(temporaryRegisters.last().get(), templateString->value()); | |
249 | } | |
250 | ||
251 | // Evaluate Expression. | |
252 | temporaryRegisters.append(generator.newTemporary()); | |
253 | generator.emitNode(temporaryRegisters.last().get(), templateExpression->value()); | |
254 | generator.emitToString(temporaryRegisters.last().get(), temporaryRegisters.last().get()); | |
255 | } | |
256 | ||
257 | // Evaluate tail TemplateString. | |
258 | if (!templateString->value()->cooked().isEmpty()) { | |
259 | temporaryRegisters.append(generator.newTemporary()); | |
260 | generator.emitNode(temporaryRegisters.last().get(), templateString->value()); | |
261 | } | |
262 | ||
263 | return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); | |
264 | } | |
265 | ||
266 | // ------------------------------ TaggedTemplateNode ----------------------------------- | |
267 | ||
268 | RegisterID* TaggedTemplateNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
269 | { | |
270 | ExpectedFunction expectedFunction = NoExpectedFunction; | |
271 | RefPtr<RegisterID> tag = nullptr; | |
272 | RefPtr<RegisterID> base = nullptr; | |
273 | if (!m_tag->isLocation()) { | |
274 | tag = generator.newTemporary(); | |
275 | tag = generator.emitNode(tag.get(), m_tag); | |
276 | } else if (m_tag->isResolveNode()) { | |
277 | ResolveNode* resolve = static_cast<ResolveNode*>(m_tag); | |
278 | const Identifier& identifier = resolve->identifier(); | |
279 | expectedFunction = generator.expectedFunctionForIdentifier(identifier); | |
280 | ||
281 | Variable var = generator.variable(identifier); | |
282 | if (RegisterID* local = var.local()) | |
283 | tag = generator.emitMove(generator.newTemporary(), local); | |
284 | else { | |
285 | tag = generator.newTemporary(); | |
286 | base = generator.newTemporary(); | |
287 | ||
288 | JSTextPosition newDivot = divotStart() + identifier.length(); | |
289 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
290 | generator.moveToDestinationIfNeeded(base.get(), generator.emitResolveScope(base.get(), var)); | |
291 | generator.emitGetFromScope(tag.get(), base.get(), var, ThrowIfNotFound); | |
292 | } | |
293 | } else if (m_tag->isBracketAccessorNode()) { | |
294 | BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(m_tag); | |
295 | base = generator.newTemporary(); | |
296 | base = generator.emitNode(base.get(), bracket->base()); | |
297 | RefPtr<RegisterID> property = generator.emitNode(bracket->subscript()); | |
298 | tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); | |
299 | } else { | |
300 | ASSERT(m_tag->isDotAccessorNode()); | |
301 | DotAccessorNode* dot = static_cast<DotAccessorNode*>(m_tag); | |
302 | base = generator.newTemporary(); | |
303 | base = generator.emitNode(base.get(), dot->base()); | |
304 | tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier()); | |
305 | } | |
306 | ||
307 | RefPtr<RegisterID> templateObject = generator.emitGetTemplateObject(generator.newTemporary(), this); | |
308 | ||
309 | unsigned expressionsCount = 0; | |
310 | for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) | |
311 | ++expressionsCount; | |
312 | ||
313 | CallArguments callArguments(generator, nullptr, 1 + expressionsCount); | |
314 | if (base) | |
315 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
316 | else | |
317 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
318 | ||
319 | unsigned argumentIndex = 0; | |
320 | generator.emitMove(callArguments.argumentRegister(argumentIndex++), templateObject.get()); | |
321 | for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) | |
322 | generator.emitNode(callArguments.argumentRegister(argumentIndex++), templateExpression->value()); | |
323 | ||
324 | return generator.emitCall(generator.finalDestination(dst, tag.get()), tag.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
f9bf01c6 | 325 | } |
ed1e77d3 | 326 | #endif |
f9bf01c6 A |
327 | |
328 | // ------------------------------ ArrayNode ------------------------------------ | |
329 | ||
330 | RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
331 | { | |
332 | // FIXME: Should we put all of this code into emitNewArray? | |
333 | ||
334 | unsigned length = 0; | |
335 | ElementNode* firstPutElement; | |
336 | for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { | |
81345200 | 337 | if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) |
f9bf01c6 A |
338 | break; |
339 | ++length; | |
340 | } | |
341 | ||
342 | if (!firstPutElement && !m_elision) | |
14957cd0 | 343 | return generator.emitNewArray(generator.finalDestination(dst), m_element, length); |
f9bf01c6 | 344 | |
14957cd0 | 345 | RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element, length); |
81345200 A |
346 | ElementNode* n = firstPutElement; |
347 | for (; n; n = n->next()) { | |
348 | if (n->value()->isSpreadExpression()) | |
349 | goto handleSpread; | |
f9bf01c6 A |
350 | RegisterID* value = generator.emitNode(n->value()); |
351 | length += n->elision(); | |
352 | generator.emitPutByIndex(array.get(), length++, value); | |
353 | } | |
354 | ||
355 | if (m_elision) { | |
14957cd0 | 356 | RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); |
f9bf01c6 A |
357 | generator.emitPutById(array.get(), generator.propertyNames().length, value); |
358 | } | |
359 | ||
360 | return generator.moveToDestinationIfNeeded(dst, array.get()); | |
81345200 A |
361 | |
362 | handleSpread: | |
363 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(length)); | |
364 | auto spreader = [this, array, index](BytecodeGenerator& generator, RegisterID* value) | |
365 | { | |
366 | generator.emitDirectPutByVal(array.get(), index.get(), value); | |
367 | generator.emitInc(index.get()); | |
368 | }; | |
369 | for (; n; n = n->next()) { | |
370 | if (n->elision()) | |
371 | generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(n->elision())), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
372 | if (n->value()->isSpreadExpression()) { | |
373 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(n->value()); | |
374 | generator.emitEnumeration(spread, spread->expression(), spreader); | |
375 | } else { | |
376 | generator.emitDirectPutByVal(array.get(), index.get(), generator.emitNode(n->value())); | |
377 | generator.emitInc(index.get()); | |
378 | } | |
379 | } | |
380 | ||
381 | if (m_elision) { | |
382 | generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(m_elision)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
383 | generator.emitPutById(array.get(), generator.propertyNames().length, index.get()); | |
384 | } | |
385 | return generator.moveToDestinationIfNeeded(dst, array.get()); | |
f9bf01c6 A |
386 | } |
387 | ||
388 | bool ArrayNode::isSimpleArray() const | |
389 | { | |
390 | if (m_elision || m_optional) | |
391 | return false; | |
392 | for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { | |
393 | if (ptr->elision()) | |
394 | return false; | |
395 | } | |
396 | return true; | |
397 | } | |
398 | ||
ed1e77d3 | 399 | ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, int lineNumber, int startPosition) const |
f9bf01c6 A |
400 | { |
401 | ASSERT(!m_elision && !m_optional); | |
402 | ElementNode* ptr = m_element; | |
403 | if (!ptr) | |
404 | return 0; | |
93a37866 A |
405 | JSTokenLocation location; |
406 | location.line = lineNumber; | |
407 | location.startOffset = startPosition; | |
ed1e77d3 | 408 | ArgumentListNode* head = new (parserArena) ArgumentListNode(location, ptr->value()); |
f9bf01c6 A |
409 | ArgumentListNode* tail = head; |
410 | ptr = ptr->next(); | |
411 | for (; ptr; ptr = ptr->next()) { | |
412 | ASSERT(!ptr->elision()); | |
ed1e77d3 | 413 | tail = new (parserArena) ArgumentListNode(location, tail, ptr->value()); |
f9bf01c6 A |
414 | } |
415 | return head; | |
416 | } | |
417 | ||
418 | // ------------------------------ ObjectLiteralNode ---------------------------- | |
419 | ||
420 | RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
421 | { | |
ed1e77d3 A |
422 | if (!m_list) { |
423 | if (dst == generator.ignoredResult()) | |
424 | return 0; | |
425 | return generator.emitNewObject(generator.finalDestination(dst)); | |
426 | } | |
427 | RefPtr<RegisterID> newObj = generator.emitNewObject(generator.tempDestination(dst)); | |
428 | generator.emitNode(newObj.get(), m_list); | |
429 | return generator.moveToDestinationIfNeeded(dst, newObj.get()); | |
f9bf01c6 A |
430 | } |
431 | ||
432 | // ------------------------------ PropertyListNode ----------------------------- | |
433 | ||
ed1e77d3 A |
434 | static inline void emitPutHomeObject(BytecodeGenerator& generator, RegisterID* function, RegisterID* homeObject) |
435 | { | |
436 | generator.emitPutById(function, generator.propertyNames().homeObjectPrivateName, homeObject); | |
437 | } | |
438 | ||
f9bf01c6 A |
439 | RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
440 | { | |
6fe7ccc8 A |
441 | // Fast case: this loop just handles regular value properties. |
442 | PropertyListNode* p = this; | |
ed1e77d3 A |
443 | for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) |
444 | emitPutConstantProperty(generator, dst, *p->m_node); | |
6fe7ccc8 A |
445 | |
446 | // Were there any get/set properties? | |
447 | if (p) { | |
ed1e77d3 A |
448 | // Build a list of getter/setter pairs to try to put them at the same time. If we encounter |
449 | // a computed property, just emit everything as that may override previous values. | |
450 | bool hasComputedProperty = false; | |
451 | ||
6fe7ccc8 | 452 | typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair; |
ed1e77d3 | 453 | typedef HashMap<UniquedStringImpl*, GetterSetterPair, IdentifierRepHash> GetterSetterMap; |
6fe7ccc8 A |
454 | GetterSetterMap map; |
455 | ||
456 | // Build a map, pairing get/set values together. | |
457 | for (PropertyListNode* q = p; q; q = q->m_next) { | |
458 | PropertyNode* node = q->m_node; | |
ed1e77d3 A |
459 | if (node->m_type & PropertyNode::Computed) { |
460 | hasComputedProperty = true; | |
461 | break; | |
462 | } | |
463 | if (node->m_type & PropertyNode::Constant) | |
6fe7ccc8 A |
464 | continue; |
465 | ||
ed1e77d3 A |
466 | // Duplicates are possible. |
467 | GetterSetterPair pair(node, static_cast<PropertyNode*>(nullptr)); | |
81345200 | 468 | GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); |
ed1e77d3 A |
469 | if (!result.isNewEntry) { |
470 | if (result.iterator->value.first->m_type == node->m_type) | |
471 | result.iterator->value.first = node; | |
472 | else | |
473 | result.iterator->value.second = node; | |
474 | } | |
6fe7ccc8 A |
475 | } |
476 | ||
477 | // Iterate over the remaining properties in the list. | |
478 | for (; p; p = p->m_next) { | |
479 | PropertyNode* node = p->m_node; | |
6fe7ccc8 A |
480 | |
481 | // Handle regular values. | |
ed1e77d3 A |
482 | if (node->m_type & PropertyNode::Constant) { |
483 | emitPutConstantProperty(generator, dst, *node); | |
6fe7ccc8 | 484 | continue; |
f9bf01c6 | 485 | } |
ed1e77d3 | 486 | |
81345200 | 487 | RegisterID* value = generator.emitNode(node->m_assign); |
ed1e77d3 A |
488 | bool isClassProperty = node->needsSuperBinding(); |
489 | if (isClassProperty) | |
490 | emitPutHomeObject(generator, value, dst); | |
491 | ||
492 | ASSERT(node->m_type & (PropertyNode::Getter | PropertyNode::Setter)); | |
493 | ||
494 | // This is a get/set property which may be overridden by a computed property later. | |
495 | if (hasComputedProperty) { | |
496 | if (node->m_type & PropertyNode::Getter) | |
497 | generator.emitPutGetterById(dst, *node->name(), value); | |
498 | else | |
499 | generator.emitPutSetterById(dst, *node->name(), value); | |
500 | continue; | |
501 | } | |
6fe7ccc8 | 502 | |
ed1e77d3 | 503 | // This is a get/set property pair. |
81345200 | 504 | GetterSetterMap::iterator it = map.find(node->name()->impl()); |
6fe7ccc8 | 505 | ASSERT(it != map.end()); |
93a37866 | 506 | GetterSetterPair& pair = it->value; |
6fe7ccc8 A |
507 | |
508 | // Was this already generated as a part of its partner? | |
509 | if (pair.second == node) | |
510 | continue; | |
ed1e77d3 | 511 | |
6fe7ccc8 A |
512 | // Generate the paired node now. |
513 | RefPtr<RegisterID> getterReg; | |
514 | RefPtr<RegisterID> setterReg; | |
ed1e77d3 | 515 | RegisterID* secondReg = nullptr; |
6fe7ccc8 | 516 | |
ed1e77d3 | 517 | if (node->m_type & PropertyNode::Getter) { |
6fe7ccc8 A |
518 | getterReg = value; |
519 | if (pair.second) { | |
ed1e77d3 | 520 | ASSERT(pair.second->m_type & PropertyNode::Setter); |
6fe7ccc8 | 521 | setterReg = generator.emitNode(pair.second->m_assign); |
ed1e77d3 | 522 | secondReg = setterReg.get(); |
6fe7ccc8 A |
523 | } else { |
524 | setterReg = generator.newTemporary(); | |
525 | generator.emitLoad(setterReg.get(), jsUndefined()); | |
526 | } | |
527 | } else { | |
ed1e77d3 | 528 | ASSERT(node->m_type & PropertyNode::Setter); |
6fe7ccc8 A |
529 | setterReg = value; |
530 | if (pair.second) { | |
ed1e77d3 | 531 | ASSERT(pair.second->m_type & PropertyNode::Getter); |
6fe7ccc8 | 532 | getterReg = generator.emitNode(pair.second->m_assign); |
ed1e77d3 | 533 | secondReg = getterReg.get(); |
6fe7ccc8 A |
534 | } else { |
535 | getterReg = generator.newTemporary(); | |
536 | generator.emitLoad(getterReg.get(), jsUndefined()); | |
537 | } | |
f9bf01c6 | 538 | } |
6fe7ccc8 | 539 | |
ed1e77d3 A |
540 | ASSERT(!pair.second || isClassProperty == pair.second->needsSuperBinding()); |
541 | if (isClassProperty && pair.second) | |
542 | emitPutHomeObject(generator, secondReg, dst); | |
543 | ||
544 | if (isClassProperty) { | |
545 | RefPtr<RegisterID> propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node->name()); | |
546 | generator.emitCallDefineProperty(dst, propertyNameRegister.get(), | |
547 | nullptr, getterReg.get(), setterReg.get(), BytecodeGenerator::PropertyConfigurable, m_position); | |
548 | } else | |
549 | generator.emitPutGetterSetter(dst, *node->name(), getterReg.get(), setterReg.get()); | |
f9bf01c6 A |
550 | } |
551 | } | |
6fe7ccc8 | 552 | |
ed1e77d3 A |
553 | return dst; |
554 | } | |
555 | ||
556 | void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node) | |
557 | { | |
558 | RefPtr<RegisterID> value = generator.emitNode(node.m_assign); | |
559 | if (node.needsSuperBinding()) { | |
560 | emitPutHomeObject(generator, value.get(), newObj); | |
561 | ||
562 | RefPtr<RegisterID> propertyNameRegister; | |
563 | if (node.name()) | |
564 | propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node.name()); | |
565 | else | |
566 | propertyNameRegister = generator.emitNode(node.m_expression); | |
567 | ||
568 | generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), | |
569 | value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); | |
570 | return; | |
571 | } | |
572 | if (const auto* identifier = node.name()) { | |
573 | Optional<uint32_t> optionalIndex = parseIndex(*identifier); | |
574 | if (!optionalIndex) { | |
575 | generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType()); | |
576 | return; | |
577 | } | |
578 | ||
579 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(optionalIndex.value())); | |
580 | generator.emitDirectPutByVal(newObj, index.get(), value.get()); | |
581 | return; | |
582 | } | |
583 | RefPtr<RegisterID> propertyName = generator.emitNode(node.m_expression); | |
584 | generator.emitDirectPutByVal(newObj, propertyName.get(), value.get()); | |
f9bf01c6 A |
585 | } |
586 | ||
587 | // ------------------------------ BracketAccessorNode -------------------------------- | |
588 | ||
589 | RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
590 | { | |
ed1e77d3 A |
591 | if (m_base->isSuperNode()) { |
592 | // FIXME: Should we generate the profiler info? | |
593 | if (m_subscript->isString()) { | |
594 | const Identifier& id = static_cast<StringNode*>(m_subscript)->value(); | |
595 | return generator.emitGetById(generator.finalDestination(dst), emitSuperBaseForCallee(generator), id); | |
596 | } | |
597 | return generator.emitGetByVal(generator.finalDestination(dst), emitSuperBaseForCallee(generator), generator.emitNode(m_subscript)); | |
598 | } | |
599 | ||
600 | RegisterID* ret; | |
601 | RegisterID* finalDest = generator.finalDestination(dst); | |
602 | ||
603 | if (m_subscript->isString()) { | |
604 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
605 | ret = generator.emitGetById(finalDest, base.get(), static_cast<StringNode*>(m_subscript)->value()); | |
606 | } else { | |
607 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); | |
608 | RegisterID* property = generator.emitNode(m_subscript); | |
609 | ret = generator.emitGetByVal(finalDest, base.get(), property); | |
14957cd0 A |
610 | } |
611 | ||
81345200 | 612 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
613 | |
614 | if (generator.vm()->typeProfiler()) { | |
615 | generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
616 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
617 | } | |
618 | return ret; | |
f9bf01c6 A |
619 | } |
620 | ||
621 | // ------------------------------ DotAccessorNode -------------------------------- | |
622 | ||
623 | RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
624 | { | |
ed1e77d3 | 625 | RefPtr<RegisterID> base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); |
81345200 | 626 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
627 | RegisterID* finalDest = generator.finalDestination(dst); |
628 | RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident); | |
629 | if (generator.vm()->typeProfiler()) { | |
630 | generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
631 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
632 | } | |
633 | return ret; | |
f9bf01c6 A |
634 | } |
635 | ||
636 | // ------------------------------ ArgumentListNode ----------------------------- | |
637 | ||
638 | RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
639 | { | |
640 | ASSERT(m_expr); | |
641 | return generator.emitNode(dst, m_expr); | |
642 | } | |
643 | ||
644 | // ------------------------------ NewExprNode ---------------------------------- | |
645 | ||
646 | RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
647 | { | |
93a37866 A |
648 | ExpectedFunction expectedFunction; |
649 | if (m_expr->isResolveNode()) | |
650 | expectedFunction = generator.expectedFunctionForIdentifier(static_cast<ResolveNode*>(m_expr)->identifier()); | |
651 | else | |
652 | expectedFunction = NoExpectedFunction; | |
f9bf01c6 | 653 | RefPtr<RegisterID> func = generator.emitNode(m_expr); |
81345200 | 654 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 | 655 | CallArguments callArguments(generator, m_args); |
ed1e77d3 | 656 | generator.emitMove(callArguments.thisRegister(), func.get()); |
81345200 | 657 | return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 A |
658 | } |
659 | ||
81345200 | 660 | CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments) |
14957cd0 | 661 | : m_argumentsNode(argumentsNode) |
81345200 | 662 | , m_padding(0) |
14957cd0 A |
663 | { |
664 | if (generator.shouldEmitProfileHooks()) | |
665 | m_profileHookRegister = generator.newTemporary(); | |
6fe7ccc8 | 666 | |
81345200 | 667 | size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register. |
14957cd0 | 668 | if (argumentsNode) { |
6fe7ccc8 A |
669 | for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next) |
670 | ++argumentCountIncludingThis; | |
671 | } | |
672 | ||
673 | m_argv.grow(argumentCountIncludingThis); | |
674 | for (int i = argumentCountIncludingThis - 1; i >= 0; --i) { | |
675 | m_argv[i] = generator.newTemporary(); | |
81345200 A |
676 | ASSERT(static_cast<size_t>(i) == m_argv.size() - 1 || m_argv[i]->index() == m_argv[i + 1]->index() - 1); |
677 | } | |
678 | ||
679 | while (stackOffset() % stackAlignmentRegisters()) { | |
680 | m_argv.insert(0, generator.newTemporary()); | |
681 | m_padding++; | |
14957cd0 | 682 | } |
6fe7ccc8 A |
683 | } |
684 | ||
f9bf01c6 A |
685 | // ------------------------------ EvalFunctionCallNode ---------------------------------- |
686 | ||
687 | RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
688 | { | |
ed1e77d3 A |
689 | Variable var = generator.variable(generator.propertyNames().eval); |
690 | if (RegisterID* local = var.local()) { | |
691 | RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); | |
81345200 A |
692 | CallArguments callArguments(generator, m_args); |
693 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
694 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); | |
695 | } | |
696 | ||
697 | RefPtr<RegisterID> func = generator.newTemporary(); | |
14957cd0 | 698 | CallArguments callArguments(generator, m_args); |
81345200 A |
699 | JSTextPosition newDivot = divotStart() + 4; |
700 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
ed1e77d3 A |
701 | generator.moveToDestinationIfNeeded( |
702 | callArguments.thisRegister(), | |
703 | generator.emitResolveScope(callArguments.thisRegister(), var)); | |
704 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); | |
81345200 | 705 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); |
f9bf01c6 A |
706 | } |
707 | ||
708 | // ------------------------------ FunctionCallValueNode ---------------------------------- | |
709 | ||
710 | RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
711 | { | |
712 | RefPtr<RegisterID> func = generator.emitNode(m_expr); | |
81345200 | 713 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 | 714 | CallArguments callArguments(generator, m_args); |
ed1e77d3 A |
715 | if (m_expr->isSuperNode()) { |
716 | ASSERT(generator.isConstructor()); | |
717 | ASSERT(generator.constructorKind() == ConstructorKind::Derived); | |
718 | generator.emitMove(callArguments.thisRegister(), generator.newTarget()); | |
719 | RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
720 | generator.emitMove(generator.thisRegister(), ret); | |
721 | return ret; | |
722 | } | |
14957cd0 | 723 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
ed1e77d3 A |
724 | RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
725 | if (generator.vm()->typeProfiler()) { | |
726 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
727 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
728 | } | |
729 | return ret; | |
f9bf01c6 A |
730 | } |
731 | ||
732 | // ------------------------------ FunctionCallResolveNode ---------------------------------- | |
733 | ||
734 | RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
735 | { | |
93a37866 | 736 | ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); |
93a37866 | 737 | |
ed1e77d3 A |
738 | Variable var = generator.variable(m_ident); |
739 | if (RegisterID* local = var.local()) { | |
740 | RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); | |
81345200 | 741 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 A |
742 | CallArguments callArguments(generator, m_args); |
743 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
93a37866 A |
744 | // This passes NoExpectedFunction because we expect that if the function is in a |
745 | // local variable, then it's not one of our built-in constructors. | |
ed1e77d3 A |
746 | RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
747 | if (generator.vm()->typeProfiler()) { | |
748 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
749 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
750 | } | |
751 | return ret; | |
f9bf01c6 A |
752 | } |
753 | ||
754 | RefPtr<RegisterID> func = generator.newTemporary(); | |
81345200 | 755 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
14957cd0 | 756 | CallArguments callArguments(generator, m_args); |
93a37866 | 757 | |
81345200 A |
758 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
759 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); | |
ed1e77d3 A |
760 | generator.moveToDestinationIfNeeded( |
761 | callArguments.thisRegister(), | |
762 | generator.emitResolveScope(callArguments.thisRegister(), var)); | |
763 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); | |
764 | RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
765 | if (generator.vm()->typeProfiler()) { | |
766 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
767 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
768 | } | |
769 | return ret; | |
770 | } | |
771 | ||
772 | // ------------------------------ BytecodeIntrinsicNode ---------------------------------- | |
773 | ||
774 | RegisterID* BytecodeIntrinsicNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
775 | { | |
776 | return (this->*m_emitter)(generator, dst); | |
777 | } | |
778 | ||
779 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByValDirect(BytecodeGenerator& generator, RegisterID* dst) | |
780 | { | |
781 | ArgumentListNode* node = m_args->m_listNode; | |
782 | RefPtr<RegisterID> base = generator.emitNode(node); | |
783 | node = node->m_next; | |
784 | RefPtr<RegisterID> index = generator.emitNode(node); | |
785 | node = node->m_next; | |
786 | RefPtr<RegisterID> value = generator.emitNode(node); | |
787 | ||
788 | ASSERT(!node->m_next); | |
789 | ||
790 | return generator.moveToDestinationIfNeeded(dst, generator.emitDirectPutByVal(base.get(), index.get(), value.get())); | |
791 | } | |
792 | ||
793 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toString(BytecodeGenerator& generator, RegisterID* dst) | |
794 | { | |
795 | ArgumentListNode* node = m_args->m_listNode; | |
796 | RefPtr<RegisterID> src = generator.emitNode(node); | |
797 | ASSERT(!node->m_next); | |
798 | ||
799 | return generator.moveToDestinationIfNeeded(dst, generator.emitToString(generator.tempDestination(dst), src.get())); | |
f9bf01c6 A |
800 | } |
801 | ||
802 | // ------------------------------ FunctionCallBracketNode ---------------------------------- | |
803 | ||
804 | RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
805 | { | |
ed1e77d3 A |
806 | bool baseIsSuper = m_base->isSuperNode(); |
807 | bool subscriptIsString = m_subscript->isString(); | |
808 | ||
809 | RefPtr<RegisterID> base; | |
810 | if (baseIsSuper) | |
811 | base = emitSuperBaseForCallee(generator); | |
812 | else { | |
813 | if (subscriptIsString) | |
814 | base = generator.emitNode(m_base); | |
815 | else | |
816 | base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); | |
817 | } | |
818 | ||
819 | RefPtr<RegisterID> function; | |
820 | if (subscriptIsString) { | |
821 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); | |
822 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value()); | |
823 | } else { | |
824 | RefPtr<RegisterID> property = generator.emitNode(m_subscript); | |
825 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); | |
826 | function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); | |
827 | } | |
828 | ||
81345200 | 829 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
14957cd0 | 830 | CallArguments callArguments(generator, m_args); |
ed1e77d3 A |
831 | if (baseIsSuper) |
832 | generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); | |
833 | else | |
834 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
835 | RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
836 | if (generator.vm()->typeProfiler()) { | |
837 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
838 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
839 | } | |
840 | return ret; | |
f9bf01c6 A |
841 | } |
842 | ||
843 | // ------------------------------ FunctionCallDotNode ---------------------------------- | |
844 | ||
845 | RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
846 | { | |
847 | RefPtr<RegisterID> function = generator.tempDestination(dst); | |
81345200 | 848 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
14957cd0 | 849 | CallArguments callArguments(generator, m_args); |
ed1e77d3 A |
850 | bool baseIsSuper = m_base->isSuperNode(); |
851 | if (baseIsSuper) | |
852 | generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); | |
853 | else | |
854 | generator.emitNode(callArguments.thisRegister(), m_base); | |
81345200 | 855 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
ed1e77d3 A |
856 | generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident); |
857 | RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
858 | if (generator.vm()->typeProfiler()) { | |
859 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
860 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
81345200 | 861 | } |
ed1e77d3 | 862 | return ret; |
f9bf01c6 A |
863 | } |
864 | ||
865 | RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
866 | { | |
867 | RefPtr<Label> realCall = generator.newLabel(); | |
868 | RefPtr<Label> end = generator.newLabel(); | |
869 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
81345200 A |
870 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
871 | RefPtr<RegisterID> function; | |
872 | bool emitCallCheck = !generator.isBuiltinFunction(); | |
873 | if (emitCallCheck) { | |
874 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName()); | |
875 | generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); | |
876 | } | |
877 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst); | |
f9bf01c6 | 878 | { |
81345200 A |
879 | if (m_args->m_listNode && m_args->m_listNode->m_expr && m_args->m_listNode->m_expr->isSpreadExpression()) { |
880 | RefPtr<RegisterID> profileHookRegister; | |
881 | if (generator.shouldEmitProfileHooks()) | |
882 | profileHookRegister = generator.newTemporary(); | |
883 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); | |
884 | ExpressionNode* subject = spread->expression(); | |
81345200 | 885 | RefPtr<RegisterID> argumentsRegister; |
ed1e77d3 A |
886 | argumentsRegister = generator.emitNode(subject); |
887 | generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); | |
888 | RefPtr<RegisterID> thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); | |
81345200 A |
889 | generator.emitCallVarargs(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, profileHookRegister.get(), divot(), divotStart(), divotEnd()); |
890 | } else if (m_args->m_listNode && m_args->m_listNode->m_expr) { | |
14957cd0 | 891 | ArgumentListNode* oldList = m_args->m_listNode; |
f9bf01c6 | 892 | m_args->m_listNode = m_args->m_listNode->m_next; |
f9bf01c6 | 893 | |
14957cd0 A |
894 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
895 | CallArguments callArguments(generator, m_args); | |
896 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); | |
81345200 | 897 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 | 898 | m_args->m_listNode = oldList; |
14957cd0 A |
899 | } else { |
900 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); | |
901 | CallArguments callArguments(generator, m_args); | |
902 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
81345200 | 903 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
14957cd0 | 904 | } |
f9bf01c6 | 905 | } |
81345200 A |
906 | if (emitCallCheck) { |
907 | generator.emitJump(end.get()); | |
908 | generator.emitLabel(realCall.get()); | |
909 | { | |
910 | CallArguments callArguments(generator, m_args); | |
911 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
912 | generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
913 | } | |
914 | generator.emitLabel(end.get()); | |
f9bf01c6 | 915 | } |
ed1e77d3 A |
916 | if (generator.vm()->typeProfiler()) { |
917 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
918 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
919 | } | |
81345200 | 920 | return returnValue.get(); |
f9bf01c6 | 921 | } |
14957cd0 | 922 | |
f9bf01c6 A |
923 | static bool areTrivialApplyArguments(ArgumentsNode* args) |
924 | { | |
925 | return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next | |
926 | || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); | |
927 | } | |
928 | ||
929 | RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
930 | { | |
931 | // A few simple cases can be trivially handled as ordinary function calls. | |
932 | // function.apply(), function.apply(arg) -> identical to function.call | |
933 | // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation | |
934 | bool mayBeCall = areTrivialApplyArguments(m_args); | |
935 | ||
936 | RefPtr<Label> realCall = generator.newLabel(); | |
937 | RefPtr<Label> end = generator.newLabel(); | |
938 | RefPtr<RegisterID> base = generator.emitNode(m_base); | |
81345200 A |
939 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
940 | RefPtr<RegisterID> function; | |
941 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); | |
942 | bool emitCallCheck = !generator.isBuiltinFunction(); | |
943 | if (emitCallCheck) { | |
944 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName()); | |
945 | generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); | |
946 | } | |
947 | if (mayBeCall) { | |
948 | if (m_args->m_listNode && m_args->m_listNode->m_expr) { | |
949 | ArgumentListNode* oldList = m_args->m_listNode; | |
950 | if (m_args->m_listNode->m_expr->isSpreadExpression()) { | |
951 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); | |
952 | RefPtr<RegisterID> profileHookRegister; | |
953 | if (generator.shouldEmitProfileHooks()) | |
954 | profileHookRegister = generator.newTemporary(); | |
955 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); | |
956 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(0)); | |
957 | RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); | |
958 | RefPtr<RegisterID> argumentsRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); | |
959 | ||
960 | auto extractor = [&thisRegister, &argumentsRegister, &index](BytecodeGenerator& generator, RegisterID* value) | |
961 | { | |
962 | RefPtr<Label> haveThis = generator.newLabel(); | |
963 | RefPtr<Label> end = generator.newLabel(); | |
964 | RefPtr<RegisterID> compareResult = generator.newTemporary(); | |
965 | RefPtr<RegisterID> indexZeroCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(0)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
966 | generator.emitJumpIfFalse(indexZeroCompareResult.get(), haveThis.get()); | |
967 | generator.emitMove(thisRegister.get(), value); | |
968 | generator.emitLoad(index.get(), jsNumber(1)); | |
969 | generator.emitJump(end.get()); | |
970 | generator.emitLabel(haveThis.get()); | |
971 | RefPtr<RegisterID> indexOneCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(1)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); | |
972 | generator.emitJumpIfFalse(indexOneCompareResult.get(), end.get()); | |
973 | generator.emitMove(argumentsRegister.get(), value); | |
974 | generator.emitLoad(index.get(), jsNumber(2)); | |
975 | generator.emitLabel(end.get()); | |
976 | }; | |
977 | generator.emitEnumeration(this, spread->expression(), extractor); | |
978 | generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd()); | |
979 | } else if (m_args->m_listNode->m_next) { | |
980 | ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); | |
981 | ASSERT(!m_args->m_listNode->m_next->m_next); | |
ed1e77d3 | 982 | m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.parserArena(), 0, 0); |
81345200 A |
983 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
984 | CallArguments callArguments(generator, m_args); | |
985 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); | |
986 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
14957cd0 | 987 | } else { |
81345200 | 988 | m_args->m_listNode = m_args->m_listNode->m_next; |
14957cd0 A |
989 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
990 | CallArguments callArguments(generator, m_args); | |
81345200 A |
991 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
992 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
14957cd0 | 993 | } |
81345200 | 994 | m_args->m_listNode = oldList; |
f9bf01c6 | 995 | } else { |
6fe7ccc8 | 996 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); |
81345200 A |
997 | CallArguments callArguments(generator, m_args); |
998 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); | |
999 | generator.emitCall(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); | |
f9bf01c6 | 1000 | } |
81345200 A |
1001 | } else { |
1002 | ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); | |
1003 | RefPtr<RegisterID> profileHookRegister; | |
1004 | if (generator.shouldEmitProfileHooks()) | |
1005 | profileHookRegister = generator.newTemporary(); | |
1006 | RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); | |
1007 | RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr); | |
1008 | RefPtr<RegisterID> argsRegister; | |
1009 | ArgumentListNode* args = m_args->m_listNode->m_next; | |
ed1e77d3 | 1010 | argsRegister = generator.emitNode(args->m_expr); |
81345200 A |
1011 | |
1012 | // Function.prototype.apply ignores extra arguments, but we still | |
1013 | // need to evaluate them for side effects. | |
1014 | while ((args = args->m_next)) | |
1015 | generator.emitNode(args->m_expr); | |
1016 | ||
1017 | generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd()); | |
f9bf01c6 | 1018 | } |
81345200 A |
1019 | if (emitCallCheck) { |
1020 | generator.emitJump(end.get()); | |
1021 | generator.emitLabel(realCall.get()); | |
14957cd0 A |
1022 | CallArguments callArguments(generator, m_args); |
1023 | generator.emitMove(callArguments.thisRegister(), base.get()); | |
81345200 A |
1024 | generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
1025 | generator.emitLabel(end.get()); | |
f9bf01c6 | 1026 | } |
ed1e77d3 A |
1027 | if (generator.vm()->typeProfiler()) { |
1028 | generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1029 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1030 | } | |
81345200 | 1031 | return returnValue.get(); |
f9bf01c6 A |
1032 | } |
1033 | ||
93a37866 | 1034 | // ------------------------------ PostfixNode ---------------------------------- |
f9bf01c6 | 1035 | |
93a37866 | 1036 | static RegisterID* emitIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) |
f9bf01c6 | 1037 | { |
93a37866 | 1038 | return (oper == OpPlusPlus) ? generator.emitInc(srcDst) : generator.emitDec(srcDst); |
f9bf01c6 A |
1039 | } |
1040 | ||
1041 | static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) | |
1042 | { | |
93a37866 A |
1043 | if (dst == srcDst) |
1044 | return generator.emitToNumber(generator.finalDestination(dst), srcDst); | |
1045 | RefPtr<RegisterID> tmp = generator.emitToNumber(generator.tempDestination(dst), srcDst); | |
1046 | emitIncOrDec(generator, srcDst, oper); | |
1047 | return generator.moveToDestinationIfNeeded(dst, tmp.get()); | |
f9bf01c6 A |
1048 | } |
1049 | ||
93a37866 | 1050 | RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1051 | { |
93a37866 A |
1052 | if (dst == generator.ignoredResult()) |
1053 | return PrefixNode::emitResolve(generator, dst); | |
f9bf01c6 | 1054 | |
93a37866 A |
1055 | ASSERT(m_expr->isResolveNode()); |
1056 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); | |
1057 | const Identifier& ident = resolve->identifier(); | |
f9bf01c6 | 1058 | |
ed1e77d3 A |
1059 | Variable var = generator.variable(ident); |
1060 | if (RegisterID* local = var.local()) { | |
1061 | RefPtr<RegisterID> localReg = local; | |
1062 | if (var.isReadOnly()) { | |
93a37866 | 1063 | generator.emitReadOnlyExceptionIfNeeded(); |
ed1e77d3 A |
1064 | localReg = generator.emitMove(generator.tempDestination(dst), local); |
1065 | } else if (generator.vm()->typeProfiler()) { | |
81345200 A |
1066 | RefPtr<RegisterID> tempDst = generator.finalDestination(dst); |
1067 | ASSERT(dst != localReg); | |
1068 | RefPtr<RegisterID> tempDstSrc = generator.newTemporary(); | |
40a37d08 A |
1069 | generator.emitToNumber(tempDst.get(), localReg.get()); |
1070 | generator.emitMove(tempDstSrc.get(), localReg.get()); | |
81345200 | 1071 | emitIncOrDec(generator, tempDstSrc.get(), m_operator); |
40a37d08 | 1072 | generator.emitMove(localReg.get(), tempDstSrc.get()); |
ed1e77d3 A |
1073 | if (generator.vm()->typeProfiler()) |
1074 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
81345200 | 1075 | return tempDst.get(); |
f9bf01c6 | 1076 | } |
40a37d08 | 1077 | return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); |
f9bf01c6 | 1078 | } |
f9bf01c6 | 1079 | |
81345200 | 1080 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
1081 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
1082 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); | |
93a37866 | 1083 | RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); |
ed1e77d3 A |
1084 | generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); |
1085 | if (generator.vm()->typeProfiler()) { | |
1086 | generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); | |
1087 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1088 | } | |
1089 | ||
93a37866 A |
1090 | return oldValue.get(); |
1091 | } | |
f9bf01c6 | 1092 | |
93a37866 | 1093 | RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1094 | { |
93a37866 A |
1095 | if (dst == generator.ignoredResult()) |
1096 | return PrefixNode::emitBracket(generator, dst); | |
1097 | ||
1098 | ASSERT(m_expr->isBracketAccessorNode()); | |
1099 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); | |
1100 | ExpressionNode* baseNode = bracketAccessor->base(); | |
1101 | ExpressionNode* subscript = bracketAccessor->subscript(); | |
1102 | ||
1103 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); | |
1104 | RefPtr<RegisterID> property = generator.emitNode(subscript); | |
f9bf01c6 | 1105 | |
81345200 | 1106 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
f9bf01c6 | 1107 | RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); |
93a37866 | 1108 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); |
81345200 | 1109 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 1110 | generator.emitPutByVal(base.get(), property.get(), value.get()); |
ed1e77d3 A |
1111 | if (generator.vm()->typeProfiler()) { |
1112 | generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1113 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1114 | } | |
93a37866 | 1115 | return generator.moveToDestinationIfNeeded(dst, oldValue); |
f9bf01c6 A |
1116 | } |
1117 | ||
93a37866 | 1118 | RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1119 | { |
93a37866 A |
1120 | if (dst == generator.ignoredResult()) |
1121 | return PrefixNode::emitDot(generator, dst); | |
f9bf01c6 | 1122 | |
93a37866 A |
1123 | ASSERT(m_expr->isDotAccessorNode()); |
1124 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); | |
1125 | ExpressionNode* baseNode = dotAccessor->base(); | |
1126 | const Identifier& ident = dotAccessor->identifier(); | |
1127 | ||
1128 | RefPtr<RegisterID> base = generator.emitNode(baseNode); | |
f9bf01c6 | 1129 | |
81345200 | 1130 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
93a37866 A |
1131 | RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident); |
1132 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); | |
81345200 | 1133 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1134 | generator.emitPutById(base.get(), ident, value.get()); |
ed1e77d3 A |
1135 | if (generator.vm()->typeProfiler()) { |
1136 | generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1137 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1138 | } | |
93a37866 A |
1139 | return generator.moveToDestinationIfNeeded(dst, oldValue); |
1140 | } | |
f9bf01c6 | 1141 | |
93a37866 | 1142 | RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1143 | { |
93a37866 A |
1144 | if (m_expr->isResolveNode()) |
1145 | return emitResolve(generator, dst); | |
1146 | ||
1147 | if (m_expr->isBracketAccessorNode()) | |
1148 | return emitBracket(generator, dst); | |
1149 | ||
1150 | if (m_expr->isDotAccessorNode()) | |
1151 | return emitDot(generator, dst); | |
1152 | ||
14957cd0 | 1153 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
ed1e77d3 A |
1154 | ? ASCIILiteral("Postfix ++ operator applied to value that is not a reference.") |
1155 | : ASCIILiteral("Postfix -- operator applied to value that is not a reference.")); | |
f9bf01c6 A |
1156 | } |
1157 | ||
1158 | // ------------------------------ DeleteResolveNode ----------------------------------- | |
1159 | ||
1160 | RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1161 | { | |
ed1e77d3 A |
1162 | Variable var = generator.variable(m_ident); |
1163 | if (var.local()) | |
f9bf01c6 A |
1164 | return generator.emitLoad(generator.finalDestination(dst), false); |
1165 | ||
81345200 | 1166 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 | 1167 | RefPtr<RegisterID> base = generator.emitResolveScope(dst, var); |
81345200 | 1168 | return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident); |
f9bf01c6 A |
1169 | } |
1170 | ||
1171 | // ------------------------------ DeleteBracketNode ----------------------------------- | |
1172 | ||
1173 | RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1174 | { | |
1175 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); | |
40a37d08 | 1176 | RefPtr<RegisterID> r1 = generator.emitNode(m_subscript); |
f9bf01c6 | 1177 | |
81345200 | 1178 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
1179 | if (m_base->isSuperNode()) |
1180 | return emitThrowReferenceError(generator, "Cannot delete a super property"); | |
40a37d08 | 1181 | return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get()); |
f9bf01c6 A |
1182 | } |
1183 | ||
1184 | // ------------------------------ DeleteDotNode ----------------------------------- | |
1185 | ||
1186 | RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1187 | { | |
40a37d08 | 1188 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); |
f9bf01c6 | 1189 | |
81345200 | 1190 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
1191 | if (m_base->isSuperNode()) |
1192 | return emitThrowReferenceError(generator, "Cannot delete a super property"); | |
40a37d08 | 1193 | return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident); |
f9bf01c6 A |
1194 | } |
1195 | ||
1196 | // ------------------------------ DeleteValueNode ----------------------------------- | |
1197 | ||
1198 | RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1199 | { | |
1200 | generator.emitNode(generator.ignoredResult(), m_expr); | |
1201 | ||
1202 | // delete on a non-location expression ignores the value and returns true | |
1203 | return generator.emitLoad(generator.finalDestination(dst), true); | |
1204 | } | |
1205 | ||
1206 | // ------------------------------ VoidNode ------------------------------------- | |
1207 | ||
1208 | RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1209 | { | |
1210 | if (dst == generator.ignoredResult()) { | |
1211 | generator.emitNode(generator.ignoredResult(), m_expr); | |
1212 | return 0; | |
1213 | } | |
1214 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); | |
1215 | return generator.emitLoad(dst, jsUndefined()); | |
1216 | } | |
1217 | ||
ed1e77d3 | 1218 | // ------------------------------ TypeOfResolveNode ----------------------------------- |
f9bf01c6 A |
1219 | |
1220 | RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1221 | { | |
ed1e77d3 A |
1222 | Variable var = generator.variable(m_ident); |
1223 | if (RegisterID* local = var.local()) { | |
f9bf01c6 A |
1224 | if (dst == generator.ignoredResult()) |
1225 | return 0; | |
ed1e77d3 | 1226 | return generator.emitTypeOf(generator.finalDestination(dst), local); |
93a37866 A |
1227 | } |
1228 | ||
ed1e77d3 A |
1229 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
1230 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); | |
f9bf01c6 A |
1231 | if (dst == generator.ignoredResult()) |
1232 | return 0; | |
81345200 | 1233 | return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get()); |
f9bf01c6 A |
1234 | } |
1235 | ||
1236 | // ------------------------------ TypeOfValueNode ----------------------------------- | |
1237 | ||
1238 | RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1239 | { | |
1240 | if (dst == generator.ignoredResult()) { | |
1241 | generator.emitNode(generator.ignoredResult(), m_expr); | |
1242 | return 0; | |
1243 | } | |
1244 | RefPtr<RegisterID> src = generator.emitNode(m_expr); | |
1245 | return generator.emitTypeOf(generator.finalDestination(dst), src.get()); | |
1246 | } | |
1247 | ||
93a37866 | 1248 | // ------------------------------ PrefixNode ---------------------------------- |
f9bf01c6 | 1249 | |
93a37866 | 1250 | RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1251 | { |
93a37866 A |
1252 | ASSERT(m_expr->isResolveNode()); |
1253 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); | |
1254 | const Identifier& ident = resolve->identifier(); | |
f9bf01c6 | 1255 | |
ed1e77d3 A |
1256 | Variable var = generator.variable(ident); |
1257 | if (RegisterID* local = var.local()) { | |
1258 | RefPtr<RegisterID> localReg = local; | |
1259 | if (var.isReadOnly()) { | |
93a37866 | 1260 | generator.emitReadOnlyExceptionIfNeeded(); |
40a37d08 | 1261 | localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); |
ed1e77d3 | 1262 | } else if (generator.vm()->typeProfiler()) { |
81345200 | 1263 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); |
40a37d08 | 1264 | generator.emitMove(tempDst.get(), localReg.get()); |
81345200 | 1265 | emitIncOrDec(generator, tempDst.get(), m_operator); |
40a37d08 | 1266 | generator.emitMove(localReg.get(), tempDst.get()); |
ed1e77d3 A |
1267 | if (generator.vm()->typeProfiler()) |
1268 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
81345200 | 1269 | return generator.moveToDestinationIfNeeded(dst, tempDst.get()); |
93a37866 | 1270 | } |
40a37d08 A |
1271 | emitIncOrDec(generator, localReg.get(), m_operator); |
1272 | return generator.moveToDestinationIfNeeded(dst, localReg.get()); | |
f9bf01c6 A |
1273 | } |
1274 | ||
81345200 | 1275 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
1276 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
1277 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); | |
81345200 | 1278 | emitIncOrDec(generator, value.get(), m_operator); |
ed1e77d3 A |
1279 | generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); |
1280 | if (generator.vm()->typeProfiler()) { | |
1281 | generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); | |
1282 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1283 | } | |
81345200 | 1284 | return generator.moveToDestinationIfNeeded(dst, value.get()); |
f9bf01c6 A |
1285 | } |
1286 | ||
93a37866 | 1287 | RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1288 | { |
93a37866 A |
1289 | ASSERT(m_expr->isBracketAccessorNode()); |
1290 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); | |
1291 | ExpressionNode* baseNode = bracketAccessor->base(); | |
1292 | ExpressionNode* subscript = bracketAccessor->subscript(); | |
1293 | ||
1294 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); | |
1295 | RefPtr<RegisterID> property = generator.emitNode(subscript); | |
f9bf01c6 A |
1296 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
1297 | ||
81345200 | 1298 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
f9bf01c6 | 1299 | RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); |
93a37866 | 1300 | emitIncOrDec(generator, value, m_operator); |
81345200 | 1301 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 1302 | generator.emitPutByVal(base.get(), property.get(), value); |
ed1e77d3 A |
1303 | if (generator.vm()->typeProfiler()) { |
1304 | generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1305 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1306 | } | |
f9bf01c6 A |
1307 | return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
1308 | } | |
1309 | ||
93a37866 | 1310 | RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1311 | { |
93a37866 A |
1312 | ASSERT(m_expr->isDotAccessorNode()); |
1313 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); | |
1314 | ExpressionNode* baseNode = dotAccessor->base(); | |
1315 | const Identifier& ident = dotAccessor->identifier(); | |
1316 | ||
1317 | RefPtr<RegisterID> base = generator.emitNode(baseNode); | |
f9bf01c6 A |
1318 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
1319 | ||
81345200 | 1320 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
93a37866 A |
1321 | RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident); |
1322 | emitIncOrDec(generator, value, m_operator); | |
81345200 | 1323 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1324 | generator.emitPutById(base.get(), ident, value); |
ed1e77d3 A |
1325 | if (generator.vm()->typeProfiler()) { |
1326 | generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1327 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1328 | } | |
f9bf01c6 A |
1329 | return generator.moveToDestinationIfNeeded(dst, propDst.get()); |
1330 | } | |
1331 | ||
93a37866 | 1332 | RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 1333 | { |
93a37866 A |
1334 | if (m_expr->isResolveNode()) |
1335 | return emitResolve(generator, dst); | |
1336 | ||
1337 | if (m_expr->isBracketAccessorNode()) | |
1338 | return emitBracket(generator, dst); | |
1339 | ||
1340 | if (m_expr->isDotAccessorNode()) | |
1341 | return emitDot(generator, dst); | |
1342 | ||
14957cd0 | 1343 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
ed1e77d3 A |
1344 | ? ASCIILiteral("Prefix ++ operator applied to value that is not a reference.") |
1345 | : ASCIILiteral("Prefix -- operator applied to value that is not a reference.")); | |
f9bf01c6 A |
1346 | } |
1347 | ||
1348 | // ------------------------------ Unary Operation Nodes ----------------------------------- | |
1349 | ||
1350 | RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1351 | { | |
40a37d08 | 1352 | RefPtr<RegisterID> src = generator.emitNode(m_expr); |
81345200 | 1353 | generator.emitExpressionInfo(position(), position(), position()); |
40a37d08 | 1354 | return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get()); |
f9bf01c6 A |
1355 | } |
1356 | ||
6fe7ccc8 A |
1357 | // ------------------------------ BitwiseNotNode ----------------------------------- |
1358 | ||
1359 | RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1360 | { | |
1361 | RefPtr<RegisterID> src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1)); | |
40a37d08 A |
1362 | RefPtr<RegisterID> src1 = generator.emitNode(m_expr); |
1363 | return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32())); | |
6fe7ccc8 A |
1364 | } |
1365 | ||
f9bf01c6 A |
1366 | // ------------------------------ LogicalNotNode ----------------------------------- |
1367 | ||
93a37866 | 1368 | void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 1369 | { |
f9bf01c6 | 1370 | // reverse the true and false targets |
93a37866 | 1371 | generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode)); |
f9bf01c6 A |
1372 | } |
1373 | ||
1374 | ||
1375 | // ------------------------------ Binary Operation Nodes ----------------------------------- | |
1376 | ||
1377 | // BinaryOpNode::emitStrcat: | |
1378 | // | |
1379 | // This node generates an op_strcat operation. This opcode can handle concatenation of three or | |
1380 | // more values, where we can determine a set of separate op_add operations would be operating on | |
1381 | // string values. | |
1382 | // | |
1383 | // This function expects to be operating on a graph of AST nodes looking something like this: | |
1384 | // | |
1385 | // (a)... (b) | |
1386 | // \ / | |
1387 | // (+) (c) | |
1388 | // \ / | |
1389 | // [d] ((+)) | |
1390 | // \ / | |
1391 | // [+=] | |
1392 | // | |
1393 | // The assignment operation is optional, if it exists the register holding the value on the | |
1394 | // lefthand side of the assignment should be passing as the optional 'lhs' argument. | |
1395 | // | |
1396 | // The method should be called on the node at the root of the tree of regular binary add | |
1397 | // operations (marked in the diagram with a double set of parentheses). This node must | |
1398 | // be performing a string concatenation (determined by statically detecting that at least | |
1399 | // one child must be a string). | |
1400 | // | |
1401 | // Since the minimum number of values being concatenated together is expected to be 3, if | |
1402 | // a lhs to a concatenating assignment is not provided then the root add should have at | |
1403 | // least one left child that is also an add that can be determined to be operating on strings. | |
1404 | // | |
1405 | RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) | |
1406 | { | |
1407 | ASSERT(isAdd()); | |
1408 | ASSERT(resultDescriptor().definitelyIsString()); | |
1409 | ||
1410 | // Create a list of expressions for all the adds in the tree of nodes we can convert into | |
1411 | // a string concatenation. The rightmost node (c) is added first. The rightmost node is | |
1412 | // added first, and the leftmost child is never added, so the vector produced for the | |
1413 | // example above will be [ c, b ]. | |
1414 | Vector<ExpressionNode*, 16> reverseExpressionList; | |
1415 | reverseExpressionList.append(m_expr2); | |
1416 | ||
1417 | // Examine the left child of the add. So long as this is a string add, add its right-child | |
1418 | // to the list, and keep processing along the left fork. | |
1419 | ExpressionNode* leftMostAddChild = m_expr1; | |
1420 | while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { | |
1421 | reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); | |
1422 | leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; | |
1423 | } | |
1424 | ||
1425 | Vector<RefPtr<RegisterID>, 16> temporaryRegisters; | |
1426 | ||
1427 | // If there is an assignment, allocate a temporary to hold the lhs after conversion. | |
1428 | // We could possibly avoid this (the lhs is converted last anyway, we could let the | |
1429 | // op_strcat node handle its conversion if required). | |
1430 | if (lhs) | |
1431 | temporaryRegisters.append(generator.newTemporary()); | |
1432 | ||
1433 | // Emit code for the leftmost node ((a) in the example). | |
1434 | temporaryRegisters.append(generator.newTemporary()); | |
1435 | RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); | |
1436 | generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); | |
1437 | ||
1438 | // Note on ordering of conversions: | |
1439 | // | |
1440 | // We maintain the same ordering of conversions as we would see if the concatenations | |
1441 | // was performed as a sequence of adds (otherwise this optimization could change | |
1442 | // behaviour should an object have been provided a valueOf or toString method). | |
1443 | // | |
1444 | // Considering the above example, the sequnce of execution is: | |
1445 | // * evaluate operand (a) | |
1446 | // * evaluate operand (b) | |
1447 | // * convert (a) to primitive <- (this would be triggered by the first add) | |
1448 | // * convert (b) to primitive <- (ditto) | |
1449 | // * evaluate operand (c) | |
1450 | // * convert (c) to primitive <- (this would be triggered by the second add) | |
1451 | // And optionally, if there is an assignment: | |
1452 | // * convert (d) to primitive <- (this would be triggered by the assigning addition) | |
1453 | // | |
1454 | // As such we do not plant an op to convert the leftmost child now. Instead, use | |
1455 | // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion | |
1456 | // once the second node has been generated. However, if the leftmost child is an | |
1457 | // immediate we can trivially determine that no conversion will be required. | |
1458 | // If this is the case | |
1459 | if (leftMostAddChild->isString()) | |
1460 | leftMostAddChildTempRegister = 0; | |
1461 | ||
1462 | while (reverseExpressionList.size()) { | |
1463 | ExpressionNode* node = reverseExpressionList.last(); | |
1464 | reverseExpressionList.removeLast(); | |
1465 | ||
1466 | // Emit the code for the current node. | |
1467 | temporaryRegisters.append(generator.newTemporary()); | |
1468 | generator.emitNode(temporaryRegisters.last().get(), node); | |
1469 | ||
1470 | // On the first iteration of this loop, when we first reach this point we have just | |
1471 | // generated the second node, which means it is time to convert the leftmost operand. | |
1472 | if (leftMostAddChildTempRegister) { | |
1473 | generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); | |
1474 | leftMostAddChildTempRegister = 0; // Only do this once. | |
1475 | } | |
1476 | // Plant a conversion for this node, if necessary. | |
1477 | if (!node->isString()) | |
1478 | generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); | |
1479 | } | |
1480 | ASSERT(temporaryRegisters.size() >= 3); | |
1481 | ||
1482 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. | |
1483 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. | |
1484 | if (emitExpressionInfoForMe) | |
81345200 | 1485 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
f9bf01c6 A |
1486 | // If there is an assignment convert the lhs now. This will also copy lhs to |
1487 | // the temporary register we allocated for it. | |
1488 | if (lhs) | |
1489 | generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); | |
1490 | ||
1491 | return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); | |
1492 | } | |
1493 | ||
93a37866 A |
1494 | void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
1495 | { | |
1496 | TriState branchCondition; | |
1497 | ExpressionNode* branchExpression; | |
1498 | tryFoldToBranch(generator, branchCondition, branchExpression); | |
1499 | ||
1500 | if (branchCondition == MixedTriState) | |
1501 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); | |
1502 | else if (branchCondition == TrueTriState) | |
1503 | generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode); | |
1504 | else | |
1505 | generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode)); | |
1506 | } | |
1507 | ||
1508 | static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant) | |
1509 | { | |
1510 | ResultType expressionType = branchExpression->resultDescriptor(); | |
1511 | ||
1512 | if (expressionType.definitelyIsBoolean() && constant.isBoolean()) | |
1513 | return true; | |
1514 | else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1)) | |
1515 | return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch. | |
1516 | else if (expressionType.isInt32() && constant.isInt32() && constant.asInt32() == 0) | |
1517 | return true; | |
1518 | ||
1519 | return false; | |
1520 | } | |
1521 | ||
1522 | void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression) | |
1523 | { | |
1524 | branchCondition = MixedTriState; | |
1525 | branchExpression = 0; | |
1526 | ||
1527 | ConstantNode* constant = 0; | |
1528 | if (m_expr1->isConstant()) { | |
1529 | constant = static_cast<ConstantNode*>(m_expr1); | |
1530 | branchExpression = m_expr2; | |
1531 | } else if (m_expr2->isConstant()) { | |
1532 | constant = static_cast<ConstantNode*>(m_expr2); | |
1533 | branchExpression = m_expr1; | |
1534 | } | |
1535 | ||
1536 | if (!constant) | |
1537 | return; | |
1538 | ASSERT(branchExpression); | |
1539 | ||
1540 | OpcodeID opcodeID = this->opcodeID(); | |
1541 | JSValue value = constant->jsValue(generator); | |
1542 | bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value); | |
1543 | if (!canFoldToBranch) | |
1544 | return; | |
1545 | ||
1546 | if (opcodeID == op_eq || opcodeID == op_stricteq) | |
1547 | branchCondition = triState(value.pureToBoolean()); | |
1548 | else if (opcodeID == op_neq || opcodeID == op_nstricteq) | |
1549 | branchCondition = triState(!value.pureToBoolean()); | |
1550 | } | |
1551 | ||
f9bf01c6 A |
1552 | RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1553 | { | |
1554 | OpcodeID opcodeID = this->opcodeID(); | |
1555 | ||
81345200 A |
1556 | if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { |
1557 | generator.emitExpressionInfo(position(), position(), position()); | |
f9bf01c6 | 1558 | return emitStrcat(generator, dst); |
81345200 | 1559 | } |
f9bf01c6 A |
1560 | |
1561 | if (opcodeID == op_neq) { | |
1562 | if (m_expr1->isNull() || m_expr2->isNull()) { | |
1563 | RefPtr<RegisterID> src = generator.tempDestination(dst); | |
1564 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); | |
1565 | return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); | |
1566 | } | |
1567 | } | |
1568 | ||
93a37866 A |
1569 | ExpressionNode* left = m_expr1; |
1570 | ExpressionNode* right = m_expr2; | |
1571 | if (opcodeID == op_neq || opcodeID == op_nstricteq) { | |
1572 | if (left->isString()) | |
1573 | std::swap(left, right); | |
1574 | } | |
1575 | ||
1576 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); | |
ed1e77d3 | 1577 | bool wasTypeof = generator.lastOpcodeID() == op_typeof; |
40a37d08 | 1578 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
81345200 | 1579 | generator.emitExpressionInfo(position(), position(), position()); |
93a37866 A |
1580 | if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { |
1581 | RefPtr<RegisterID> tmp = generator.tempDestination(dst); | |
1582 | if (opcodeID == op_neq) | |
40a37d08 | 1583 | generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
93a37866 | 1584 | else if (opcodeID == op_nstricteq) |
40a37d08 | 1585 | generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
93a37866 A |
1586 | else |
1587 | RELEASE_ASSERT_NOT_REACHED(); | |
1588 | return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get()); | |
1589 | } | |
40a37d08 | 1590 | RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor())); |
81345200 A |
1591 | if (opcodeID == op_urshift && dst != generator.ignoredResult()) |
1592 | return generator.emitUnaryOp(op_unsigned, result, result); | |
1593 | return result; | |
f9bf01c6 A |
1594 | } |
1595 | ||
1596 | RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1597 | { | |
1598 | if (m_expr1->isNull() || m_expr2->isNull()) { | |
1599 | RefPtr<RegisterID> src = generator.tempDestination(dst); | |
1600 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); | |
1601 | return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); | |
1602 | } | |
1603 | ||
93a37866 A |
1604 | ExpressionNode* left = m_expr1; |
1605 | ExpressionNode* right = m_expr2; | |
1606 | if (left->isString()) | |
1607 | std::swap(left, right); | |
1608 | ||
1609 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 A |
1610 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
1611 | return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); | |
f9bf01c6 A |
1612 | } |
1613 | ||
1614 | RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1615 | { | |
93a37866 A |
1616 | ExpressionNode* left = m_expr1; |
1617 | ExpressionNode* right = m_expr2; | |
1618 | if (left->isString()) | |
1619 | std::swap(left, right); | |
1620 | ||
1621 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 A |
1622 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
1623 | return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); | |
f9bf01c6 A |
1624 | } |
1625 | ||
f9bf01c6 A |
1626 | RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1627 | { | |
1628 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); | |
40a37d08 | 1629 | RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); |
81345200 | 1630 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1631 | return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); |
f9bf01c6 A |
1632 | } |
1633 | ||
1634 | RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1635 | { | |
1636 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); | |
1637 | RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); | |
93a37866 A |
1638 | RefPtr<RegisterID> prototype = generator.newTemporary(); |
1639 | RefPtr<RegisterID> dstReg = generator.finalDestination(dst, src1.get()); | |
1640 | RefPtr<Label> target = generator.newLabel(); | |
f9bf01c6 | 1641 | |
81345200 | 1642 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1643 | generator.emitCheckHasInstance(dstReg.get(), src1.get(), src2.get(), target.get()); |
14957cd0 | 1644 | |
81345200 | 1645 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 | 1646 | generator.emitGetById(prototype.get(), src2.get(), generator.vm()->propertyNames->prototype); |
f9bf01c6 | 1647 | |
81345200 | 1648 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
93a37866 A |
1649 | RegisterID* result = generator.emitInstanceOf(dstReg.get(), src1.get(), prototype.get()); |
1650 | generator.emitLabel(target.get()); | |
1651 | return result; | |
f9bf01c6 A |
1652 | } |
1653 | ||
1654 | // ------------------------------ LogicalOpNode ---------------------------- | |
1655 | ||
1656 | RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1657 | { | |
1658 | RefPtr<RegisterID> temp = generator.tempDestination(dst); | |
1659 | RefPtr<Label> target = generator.newLabel(); | |
1660 | ||
1661 | generator.emitNode(temp.get(), m_expr1); | |
1662 | if (m_operator == OpLogicalAnd) | |
1663 | generator.emitJumpIfFalse(temp.get(), target.get()); | |
1664 | else | |
1665 | generator.emitJumpIfTrue(temp.get(), target.get()); | |
1666 | generator.emitNode(temp.get(), m_expr2); | |
1667 | generator.emitLabel(target.get()); | |
1668 | ||
1669 | return generator.moveToDestinationIfNeeded(dst, temp.get()); | |
1670 | } | |
1671 | ||
93a37866 | 1672 | void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 1673 | { |
93a37866 A |
1674 | RefPtr<Label> afterExpr1 = generator.newLabel(); |
1675 | if (m_operator == OpLogicalAnd) | |
1676 | generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, FallThroughMeansTrue); | |
1677 | else | |
1678 | generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), FallThroughMeansFalse); | |
1679 | generator.emitLabel(afterExpr1.get()); | |
f9bf01c6 | 1680 | |
93a37866 | 1681 | generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMode); |
f9bf01c6 A |
1682 | } |
1683 | ||
1684 | // ------------------------------ ConditionalNode ------------------------------ | |
1685 | ||
1686 | RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1687 | { | |
1688 | RefPtr<RegisterID> newDst = generator.finalDestination(dst); | |
1689 | RefPtr<Label> beforeElse = generator.newLabel(); | |
1690 | RefPtr<Label> afterElse = generator.newLabel(); | |
1691 | ||
93a37866 A |
1692 | RefPtr<Label> beforeThen = generator.newLabel(); |
1693 | generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); | |
1694 | generator.emitLabel(beforeThen.get()); | |
f9bf01c6 | 1695 | |
ed1e77d3 | 1696 | generator.emitProfileControlFlow(m_expr1->startOffset()); |
f9bf01c6 A |
1697 | generator.emitNode(newDst.get(), m_expr1); |
1698 | generator.emitJump(afterElse.get()); | |
1699 | ||
1700 | generator.emitLabel(beforeElse.get()); | |
ed1e77d3 | 1701 | generator.emitProfileControlFlow(m_expr1->endOffset() + 1); |
f9bf01c6 A |
1702 | generator.emitNode(newDst.get(), m_expr2); |
1703 | ||
1704 | generator.emitLabel(afterElse.get()); | |
1705 | ||
ed1e77d3 A |
1706 | generator.emitProfileControlFlow(m_expr2->endOffset() + 1); |
1707 | ||
f9bf01c6 A |
1708 | return newDst.get(); |
1709 | } | |
1710 | ||
1711 | // ------------------------------ ReadModifyResolveNode ----------------------------------- | |
1712 | ||
1713 | // FIXME: should this be moved to be a method on BytecodeGenerator? | |
1714 | static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) | |
1715 | { | |
1716 | OpcodeID opcodeID; | |
1717 | switch (oper) { | |
1718 | case OpMultEq: | |
1719 | opcodeID = op_mul; | |
1720 | break; | |
1721 | case OpDivEq: | |
1722 | opcodeID = op_div; | |
1723 | break; | |
1724 | case OpPlusEq: | |
1725 | if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) | |
1726 | return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); | |
1727 | opcodeID = op_add; | |
1728 | break; | |
1729 | case OpMinusEq: | |
1730 | opcodeID = op_sub; | |
1731 | break; | |
1732 | case OpLShift: | |
1733 | opcodeID = op_lshift; | |
1734 | break; | |
1735 | case OpRShift: | |
1736 | opcodeID = op_rshift; | |
1737 | break; | |
1738 | case OpURShift: | |
1739 | opcodeID = op_urshift; | |
1740 | break; | |
1741 | case OpAndEq: | |
1742 | opcodeID = op_bitand; | |
1743 | break; | |
1744 | case OpXOrEq: | |
1745 | opcodeID = op_bitxor; | |
1746 | break; | |
1747 | case OpOrEq: | |
1748 | opcodeID = op_bitor; | |
1749 | break; | |
1750 | case OpModEq: | |
1751 | opcodeID = op_mod; | |
1752 | break; | |
1753 | default: | |
93a37866 | 1754 | RELEASE_ASSERT_NOT_REACHED(); |
f9bf01c6 A |
1755 | return dst; |
1756 | } | |
1757 | ||
1758 | RegisterID* src2 = generator.emitNode(m_right); | |
1759 | ||
1760 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. | |
1761 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. | |
1762 | if (emitExpressionInfoForMe) | |
81345200 A |
1763 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
1764 | RegisterID* result = generator.emitBinaryOp(opcodeID, dst, src1, src2, types); | |
1765 | if (oper == OpURShift) | |
1766 | return generator.emitUnaryOp(op_unsigned, result, result); | |
1767 | return result; | |
f9bf01c6 A |
1768 | } |
1769 | ||
1770 | RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1771 | { | |
ed1e77d3 A |
1772 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
1773 | Variable var = generator.variable(m_ident); | |
1774 | if (RegisterID* local = var.local()) { | |
1775 | if (var.isReadOnly()) { | |
93a37866 | 1776 | generator.emitReadOnlyExceptionIfNeeded(); |
ed1e77d3 | 1777 | return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
93a37866 A |
1778 | } |
1779 | ||
ed1e77d3 | 1780 | if (generator.vm()->typeProfiler() |
81345200 | 1781 | || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { |
f9bf01c6 | 1782 | RefPtr<RegisterID> result = generator.newTemporary(); |
ed1e77d3 | 1783 | generator.emitMove(result.get(), local); |
f9bf01c6 | 1784 | emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
ed1e77d3 A |
1785 | generator.emitMove(local, result.get()); |
1786 | generator.invalidateForInContextForLocal(local); | |
1787 | if (generator.vm()->typeProfiler()) | |
1788 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
f9bf01c6 A |
1789 | return generator.moveToDestinationIfNeeded(dst, result.get()); |
1790 | } | |
1791 | ||
ed1e77d3 A |
1792 | RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
1793 | generator.invalidateForInContextForLocal(local); | |
f9bf01c6 A |
1794 | return generator.moveToDestinationIfNeeded(dst, result); |
1795 | } | |
1796 | ||
81345200 | 1797 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); |
ed1e77d3 A |
1798 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
1799 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); | |
81345200 | 1800 | RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); |
ed1e77d3 A |
1801 | RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound); |
1802 | if (generator.vm()->typeProfiler()) { | |
1803 | generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); | |
1804 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1805 | } | |
1806 | return returnResult; | |
f9bf01c6 A |
1807 | } |
1808 | ||
1809 | // ------------------------------ AssignResolveNode ----------------------------------- | |
1810 | ||
1811 | RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1812 | { | |
ed1e77d3 A |
1813 | Variable var = generator.variable(m_ident); |
1814 | if (RegisterID* local = var.local()) { | |
1815 | if (var.isReadOnly()) { | |
93a37866 | 1816 | generator.emitReadOnlyExceptionIfNeeded(); |
f9bf01c6 | 1817 | return generator.emitNode(dst, m_right); |
93a37866 | 1818 | } |
ed1e77d3 | 1819 | if (var.isSpecial() || generator.vm()->typeProfiler()) { |
81345200 A |
1820 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); |
1821 | generator.emitNode(tempDst.get(), m_right); | |
ed1e77d3 A |
1822 | generator.emitMove(local, tempDst.get()); |
1823 | generator.invalidateForInContextForLocal(local); | |
1824 | if (generator.vm()->typeProfiler()) | |
1825 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
81345200 A |
1826 | return generator.moveToDestinationIfNeeded(dst, tempDst.get()); |
1827 | } | |
ed1e77d3 A |
1828 | RegisterID* result = generator.emitNode(local, m_right); |
1829 | generator.invalidateForInContextForLocal(local); | |
f9bf01c6 A |
1830 | return generator.moveToDestinationIfNeeded(dst, result); |
1831 | } | |
1832 | ||
81345200 A |
1833 | if (generator.isStrictMode()) |
1834 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
ed1e77d3 | 1835 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
f9bf01c6 A |
1836 | if (dst == generator.ignoredResult()) |
1837 | dst = 0; | |
81345200 A |
1838 | RefPtr<RegisterID> result = generator.emitNode(dst, m_right); |
1839 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
ed1e77d3 A |
1840 | RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); |
1841 | if (generator.vm()->typeProfiler()) { | |
1842 | generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); | |
1843 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1844 | } | |
1845 | return returnResult; | |
f9bf01c6 A |
1846 | } |
1847 | ||
1848 | // ------------------------------ AssignDotNode ----------------------------------- | |
1849 | ||
1850 | RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1851 | { | |
1852 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); | |
1853 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); | |
40a37d08 | 1854 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
81345200 | 1855 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1856 | RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); |
6fe7ccc8 | 1857 | generator.emitPutById(base.get(), m_ident, forwardResult); |
ed1e77d3 A |
1858 | if (generator.vm()->typeProfiler()) { |
1859 | generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1860 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1861 | } | |
6fe7ccc8 | 1862 | return generator.moveToDestinationIfNeeded(dst, forwardResult); |
f9bf01c6 A |
1863 | } |
1864 | ||
1865 | // ------------------------------ ReadModifyDotNode ----------------------------------- | |
1866 | ||
1867 | RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1868 | { | |
1869 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); | |
1870 | ||
81345200 | 1871 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
f9bf01c6 | 1872 | RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
81345200 | 1873 | 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 | 1874 | |
81345200 | 1875 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
1876 | RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue); |
1877 | if (generator.vm()->typeProfiler()) { | |
1878 | generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1879 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1880 | } | |
1881 | return ret; | |
f9bf01c6 A |
1882 | } |
1883 | ||
1884 | // ------------------------------ AssignErrorNode ----------------------------------- | |
1885 | ||
1886 | RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
1887 | { | |
ed1e77d3 | 1888 | return emitThrowReferenceError(generator, ASCIILiteral("Left side of assignment is not a reference.")); |
f9bf01c6 A |
1889 | } |
1890 | ||
1891 | // ------------------------------ AssignBracketNode ----------------------------------- | |
1892 | ||
1893 | RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1894 | { | |
1895 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); | |
1896 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); | |
1897 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); | |
40a37d08 | 1898 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
f9bf01c6 | 1899 | |
81345200 | 1900 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
40a37d08 | 1901 | RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); |
ed1e77d3 A |
1902 | |
1903 | if (m_subscript->isString()) | |
1904 | generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult); | |
1905 | else | |
1906 | generator.emitPutByVal(base.get(), property.get(), forwardResult); | |
1907 | ||
1908 | if (generator.vm()->typeProfiler()) { | |
1909 | generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1910 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1911 | } | |
6fe7ccc8 | 1912 | return generator.moveToDestinationIfNeeded(dst, forwardResult); |
f9bf01c6 A |
1913 | } |
1914 | ||
1915 | // ------------------------------ ReadModifyBracketNode ----------------------------------- | |
1916 | ||
1917 | RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1918 | { | |
1919 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); | |
1920 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); | |
1921 | ||
81345200 | 1922 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
f9bf01c6 | 1923 | RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
81345200 | 1924 | 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 | 1925 | |
81345200 | 1926 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 1927 | generator.emitPutByVal(base.get(), property.get(), updatedValue); |
ed1e77d3 A |
1928 | if (generator.vm()->typeProfiler()) { |
1929 | generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
1930 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
1931 | } | |
f9bf01c6 A |
1932 | |
1933 | return updatedValue; | |
1934 | } | |
1935 | ||
1936 | // ------------------------------ CommaNode ------------------------------------ | |
1937 | ||
1938 | RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
1939 | { | |
ed1e77d3 A |
1940 | CommaNode* node = this; |
1941 | for (; node && node->next(); node = node->next()) | |
1942 | generator.emitNode(generator.ignoredResult(), node->m_expr); | |
1943 | return generator.emitNode(dst, node->m_expr); | |
f9bf01c6 A |
1944 | } |
1945 | ||
1946 | // ------------------------------ ConstDeclNode ------------------------------------ | |
1947 | ||
1948 | RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) | |
1949 | { | |
6fe7ccc8 | 1950 | // FIXME: This code does not match the behavior of const in Firefox. |
ed1e77d3 A |
1951 | Variable var = generator.variable(m_ident); |
1952 | if (RegisterID* local = var.local()) { | |
f9bf01c6 | 1953 | if (!m_init) |
ed1e77d3 | 1954 | return local; |
f9bf01c6 | 1955 | |
ed1e77d3 A |
1956 | // FIXME: Maybe call emitExpressionInfo here. |
1957 | if (var.isSpecial() || generator.vm()->typeProfiler()) { | |
81345200 A |
1958 | RefPtr<RegisterID> tempDst = generator.newTemporary(); |
1959 | generator.emitNode(tempDst.get(), m_init); | |
ed1e77d3 | 1960 | return generator.emitMove(local, tempDst.get()); |
81345200 A |
1961 | } |
1962 | ||
ed1e77d3 | 1963 | return generator.emitNode(local, m_init); |
f9bf01c6 A |
1964 | } |
1965 | ||
6fe7ccc8 A |
1966 | RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); |
1967 | ||
93a37866 A |
1968 | if (generator.codeType() == GlobalCode) |
1969 | return generator.emitInitGlobalConst(m_ident, value.get()); | |
6fe7ccc8 | 1970 | |
ed1e77d3 A |
1971 | if (generator.codeType() != EvalCode) { |
1972 | // Do a special kind of resolution. If anything fails, then don't perform the assignment. This is | |
1973 | // pretty shady - particularly how negligent it is with inteleaving scopes - but it's the | |
1974 | // behavior that JSC has had for a long time. | |
1975 | ||
1976 | ASSERT(generator.codeType() == FunctionCode); | |
1977 | ||
1978 | var = generator.variablePerSymbolTable(m_ident); | |
1979 | if (!var.isResolved()) | |
1980 | return value.get(); | |
1981 | ||
1982 | RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var); | |
1983 | return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); | |
1984 | } | |
6fe7ccc8 | 1985 | |
93a37866 | 1986 | // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope. |
ed1e77d3 A |
1987 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
1988 | return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); | |
f9bf01c6 A |
1989 | } |
1990 | ||
1991 | RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
1992 | { | |
1993 | RegisterID* result = 0; | |
1994 | for (ConstDeclNode* n = this; n; n = n->m_next) | |
1995 | result = n->emitCodeSingle(generator); | |
1996 | ||
1997 | return result; | |
1998 | } | |
1999 | ||
2000 | // ------------------------------ ConstStatementNode ----------------------------- | |
2001 | ||
93a37866 | 2002 | void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2003 | { |
81345200 | 2004 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 2005 | generator.emitNode(m_next); |
f9bf01c6 A |
2006 | } |
2007 | ||
2008 | // ------------------------------ SourceElements ------------------------------- | |
2009 | ||
2010 | ||
2011 | inline StatementNode* SourceElements::lastStatement() const | |
2012 | { | |
ed1e77d3 | 2013 | return m_tail; |
f9bf01c6 A |
2014 | } |
2015 | ||
2016 | inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2017 | { | |
ed1e77d3 A |
2018 | for (StatementNode* statement = m_head; statement; statement = statement->next()) |
2019 | generator.emitNode(dst, statement); | |
f9bf01c6 A |
2020 | } |
2021 | ||
2022 | // ------------------------------ BlockNode ------------------------------------ | |
2023 | ||
2024 | inline StatementNode* BlockNode::lastStatement() const | |
2025 | { | |
2026 | return m_statements ? m_statements->lastStatement() : 0; | |
2027 | } | |
2028 | ||
ed1e77d3 | 2029 | StatementNode* BlockNode::singleStatement() const |
14957cd0 A |
2030 | { |
2031 | return m_statements ? m_statements->singleStatement() : 0; | |
2032 | } | |
2033 | ||
93a37866 | 2034 | void BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2035 | { |
93a37866 A |
2036 | if (!m_statements) |
2037 | return; | |
2038 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
2039 | } |
2040 | ||
2041 | // ------------------------------ EmptyStatementNode --------------------------- | |
2042 | ||
93a37866 | 2043 | void EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2044 | { |
81345200 | 2045 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2046 | } |
2047 | ||
2048 | // ------------------------------ DebuggerStatementNode --------------------------- | |
2049 | ||
93a37866 | 2050 | void DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2051 | { |
81345200 | 2052 | generator.emitDebugHook(DidReachBreakpoint, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2053 | } |
2054 | ||
2055 | // ------------------------------ ExprStatementNode ---------------------------- | |
2056 | ||
93a37866 | 2057 | void ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
2058 | { |
2059 | ASSERT(m_expr); | |
81345200 | 2060 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 2061 | generator.emitNode(dst, m_expr); |
f9bf01c6 A |
2062 | } |
2063 | ||
2064 | // ------------------------------ VarStatementNode ---------------------------- | |
2065 | ||
93a37866 | 2066 | void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 A |
2067 | { |
2068 | ASSERT(m_expr); | |
81345200 | 2069 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 | 2070 | generator.emitNode(m_expr); |
f9bf01c6 A |
2071 | } |
2072 | ||
ed1e77d3 A |
2073 | // ------------------------------ EmptyVarExpression ---------------------------- |
2074 | ||
2075 | RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
2076 | { | |
2077 | if (!generator.vm()->typeProfiler()) | |
2078 | return nullptr; | |
2079 | ||
2080 | Variable var = generator.variable(m_ident); | |
2081 | if (RegisterID* local = var.local()) | |
2082 | generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); | |
2083 | else { | |
2084 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); | |
2085 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); | |
2086 | generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); | |
2087 | } | |
2088 | ||
2089 | generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); | |
2090 | ||
2091 | // It's safe to return null here because this node will always be a child node of VarStatementNode which ignores our return value. | |
2092 | return nullptr; | |
2093 | } | |
2094 | ||
93a37866 | 2095 | // ------------------------------ IfElseNode --------------------------------------- |
f9bf01c6 | 2096 | |
93a37866 | 2097 | static inline StatementNode* singleStatement(StatementNode* statementNode) |
f9bf01c6 | 2098 | { |
93a37866 A |
2099 | if (statementNode->isBlock()) |
2100 | return static_cast<BlockNode*>(statementNode)->singleStatement(); | |
2101 | return statementNode; | |
2102 | } | |
f9bf01c6 | 2103 | |
93a37866 A |
2104 | bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock, |
2105 | Label*& trueTarget, FallThroughMode& fallThroughMode) | |
2106 | { | |
2107 | StatementNode* singleStatement = JSC::singleStatement(ifBlock); | |
2108 | if (!singleStatement) | |
2109 | return false; | |
2110 | ||
2111 | if (singleStatement->isBreak()) { | |
2112 | BreakNode* breakNode = static_cast<BreakNode*>(singleStatement); | |
2113 | Label* target = breakNode->trivialTarget(generator); | |
2114 | if (!target) | |
2115 | return false; | |
2116 | trueTarget = target; | |
2117 | fallThroughMode = FallThroughMeansFalse; | |
2118 | return true; | |
f9bf01c6 A |
2119 | } |
2120 | ||
93a37866 A |
2121 | if (singleStatement->isContinue()) { |
2122 | ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement); | |
2123 | Label* target = continueNode->trivialTarget(generator); | |
2124 | if (!target) | |
2125 | return false; | |
2126 | trueTarget = target; | |
2127 | fallThroughMode = FallThroughMeansFalse; | |
2128 | return true; | |
2129 | } | |
f9bf01c6 | 2130 | |
93a37866 | 2131 | return false; |
f9bf01c6 A |
2132 | } |
2133 | ||
93a37866 | 2134 | void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2135 | { |
81345200 | 2136 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2137 | |
93a37866 | 2138 | RefPtr<Label> beforeThen = generator.newLabel(); |
f9bf01c6 A |
2139 | RefPtr<Label> beforeElse = generator.newLabel(); |
2140 | RefPtr<Label> afterElse = generator.newLabel(); | |
2141 | ||
93a37866 A |
2142 | Label* trueTarget = beforeThen.get(); |
2143 | Label* falseTarget = beforeElse.get(); | |
2144 | FallThroughMode fallThroughMode = FallThroughMeansTrue; | |
2145 | bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode); | |
f9bf01c6 | 2146 | |
93a37866 A |
2147 | generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode); |
2148 | generator.emitLabel(beforeThen.get()); | |
ed1e77d3 | 2149 | generator.emitProfileControlFlow(m_ifBlock->startOffset()); |
93a37866 A |
2150 | |
2151 | if (!didFoldIfBlock) { | |
2152 | generator.emitNode(dst, m_ifBlock); | |
2153 | if (m_elseBlock) | |
2154 | generator.emitJump(afterElse.get()); | |
2155 | } | |
f9bf01c6 A |
2156 | |
2157 | generator.emitLabel(beforeElse.get()); | |
2158 | ||
ed1e77d3 A |
2159 | if (m_elseBlock) { |
2160 | generator.emitProfileControlFlow(m_ifBlock->endOffset() + (m_ifBlock->isBlock() ? 1 : 0)); | |
93a37866 | 2161 | generator.emitNode(dst, m_elseBlock); |
ed1e77d3 | 2162 | } |
f9bf01c6 A |
2163 | |
2164 | generator.emitLabel(afterElse.get()); | |
ed1e77d3 A |
2165 | StatementNode* endingBlock = m_elseBlock ? m_elseBlock : m_ifBlock; |
2166 | generator.emitProfileControlFlow(endingBlock->endOffset() + (endingBlock->isBlock() ? 1 : 0)); | |
f9bf01c6 A |
2167 | } |
2168 | ||
2169 | // ------------------------------ DoWhileNode ---------------------------------- | |
2170 | ||
93a37866 | 2171 | void DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2172 | { |
93a37866 | 2173 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
f9bf01c6 A |
2174 | |
2175 | RefPtr<Label> topOfLoop = generator.newLabel(); | |
2176 | generator.emitLabel(topOfLoop.get()); | |
6fe7ccc8 | 2177 | generator.emitLoopHint(); |
81345200 | 2178 | generator.emitDebugHook(WillExecuteStatement, lastLine(), startOffset(), lineStartOffset()); |
93a37866 A |
2179 | |
2180 | generator.emitNode(dst, m_statement); | |
f9bf01c6 A |
2181 | |
2182 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 2183 | generator.emitDebugHook(WillExecuteStatement, lastLine(), startOffset(), lineStartOffset()); |
93a37866 | 2184 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
f9bf01c6 A |
2185 | |
2186 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
2187 | } |
2188 | ||
2189 | // ------------------------------ WhileNode ------------------------------------ | |
2190 | ||
93a37866 | 2191 | void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2192 | { |
93a37866 A |
2193 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
2194 | RefPtr<Label> topOfLoop = generator.newLabel(); | |
f9bf01c6 | 2195 | |
ed1e77d3 | 2196 | generator.emitDebugHook(WillExecuteStatement, m_expr->firstLine(), m_expr->startOffset(), m_expr->lineStartOffset()); |
93a37866 | 2197 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); |
f9bf01c6 | 2198 | |
f9bf01c6 | 2199 | generator.emitLabel(topOfLoop.get()); |
6fe7ccc8 | 2200 | generator.emitLoopHint(); |
f9bf01c6 | 2201 | |
ed1e77d3 | 2202 | generator.emitProfileControlFlow(m_statement->startOffset()); |
f9bf01c6 A |
2203 | generator.emitNode(dst, m_statement); |
2204 | ||
2205 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 2206 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2207 | |
93a37866 | 2208 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
f9bf01c6 A |
2209 | |
2210 | generator.emitLabel(scope->breakTarget()); | |
ed1e77d3 A |
2211 | |
2212 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); | |
f9bf01c6 A |
2213 | } |
2214 | ||
2215 | // ------------------------------ ForNode -------------------------------------- | |
2216 | ||
93a37866 | 2217 | void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2218 | { |
93a37866 | 2219 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); |
f9bf01c6 | 2220 | |
81345200 | 2221 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2222 | |
2223 | if (m_expr1) | |
2224 | generator.emitNode(generator.ignoredResult(), m_expr1); | |
93a37866 | 2225 | |
f9bf01c6 | 2226 | RefPtr<Label> topOfLoop = generator.newLabel(); |
93a37866 A |
2227 | if (m_expr2) |
2228 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); | |
2229 | ||
f9bf01c6 | 2230 | generator.emitLabel(topOfLoop.get()); |
6fe7ccc8 | 2231 | generator.emitLoopHint(); |
ed1e77d3 | 2232 | generator.emitProfileControlFlow(m_statement->startOffset()); |
f9bf01c6 | 2233 | |
93a37866 | 2234 | generator.emitNode(dst, m_statement); |
f9bf01c6 A |
2235 | |
2236 | generator.emitLabel(scope->continueTarget()); | |
81345200 | 2237 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2238 | if (m_expr3) |
2239 | generator.emitNode(generator.ignoredResult(), m_expr3); | |
2240 | ||
93a37866 A |
2241 | if (m_expr2) |
2242 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); | |
2243 | else | |
f9bf01c6 A |
2244 | generator.emitJump(topOfLoop.get()); |
2245 | ||
2246 | generator.emitLabel(scope->breakTarget()); | |
ed1e77d3 | 2247 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); |
f9bf01c6 A |
2248 | } |
2249 | ||
2250 | // ------------------------------ ForInNode ------------------------------------ | |
2251 | ||
ed1e77d3 | 2252 | RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator) |
f9bf01c6 | 2253 | { |
ed1e77d3 A |
2254 | if (m_lexpr->isResolveNode()) { |
2255 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); | |
2256 | return generator.variable(ident).local(); | |
93a37866 | 2257 | } |
f9bf01c6 | 2258 | |
ed1e77d3 A |
2259 | if (m_lexpr->isDestructuringNode()) { |
2260 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); | |
2261 | auto binding = assignNode->bindings(); | |
2262 | if (!binding->isBindingNode()) | |
2263 | return nullptr; | |
f9bf01c6 | 2264 | |
ed1e77d3 A |
2265 | auto simpleBinding = static_cast<BindingNode*>(binding); |
2266 | const Identifier& ident = simpleBinding->boundProperty(); | |
2267 | Variable var = generator.variable(ident); | |
2268 | if (var.isSpecial()) | |
2269 | return nullptr; | |
2270 | return var.local(); | |
2271 | } | |
f9bf01c6 | 2272 | |
ed1e77d3 A |
2273 | return nullptr; |
2274 | } | |
f9bf01c6 | 2275 | |
ed1e77d3 A |
2276 | void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propertyName) |
2277 | { | |
f9bf01c6 A |
2278 | if (m_lexpr->isResolveNode()) { |
2279 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); | |
ed1e77d3 A |
2280 | Variable var = generator.variable(ident); |
2281 | if (RegisterID* local = var.local()) | |
2282 | generator.emitMove(local, propertyName); | |
2283 | else { | |
81345200 A |
2284 | if (generator.isStrictMode()) |
2285 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
ed1e77d3 | 2286 | RegisterID* scope = generator.emitResolveScope(nullptr, var); |
81345200 | 2287 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
2288 | generator.emitPutToScope(scope, var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); |
2289 | if (generator.vm()->typeProfiler()) | |
2290 | generator.emitProfileType(propertyName, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); | |
f9bf01c6 | 2291 | } |
ed1e77d3 A |
2292 | if (generator.vm()->typeProfiler()) |
2293 | generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); | |
2294 | return; | |
2295 | } | |
2296 | if (m_lexpr->isDotAccessorNode()) { | |
f9bf01c6 A |
2297 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); |
2298 | const Identifier& ident = assignNode->identifier(); | |
f9bf01c6 | 2299 | RegisterID* base = generator.emitNode(assignNode->base()); |
81345200 | 2300 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
f9bf01c6 | 2301 | generator.emitPutById(base, ident, propertyName); |
ed1e77d3 A |
2302 | if (generator.vm()->typeProfiler()) { |
2303 | generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
2304 | generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); | |
2305 | } | |
2306 | return; | |
2307 | } | |
2308 | if (m_lexpr->isBracketAccessorNode()) { | |
f9bf01c6 | 2309 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); |
f9bf01c6 A |
2310 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
2311 | RegisterID* subscript = generator.emitNode(assignNode->subscript()); | |
81345200 | 2312 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
f9bf01c6 | 2313 | generator.emitPutByVal(base.get(), subscript, propertyName); |
ed1e77d3 A |
2314 | if (generator.vm()->typeProfiler()) { |
2315 | generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
2316 | generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); | |
2317 | } | |
2318 | return; | |
2319 | } | |
2320 | ||
2321 | if (m_lexpr->isDestructuringNode()) { | |
2322 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); | |
81345200 | 2323 | auto binding = assignNode->bindings(); |
ed1e77d3 | 2324 | if (!binding->isBindingNode()) { |
81345200 | 2325 | assignNode->bindings()->bindValue(generator, propertyName); |
ed1e77d3 | 2326 | return; |
81345200 | 2327 | } |
ed1e77d3 A |
2328 | |
2329 | auto simpleBinding = static_cast<BindingNode*>(binding); | |
2330 | const Identifier& ident = simpleBinding->boundProperty(); | |
2331 | Variable var = generator.variable(ident); | |
2332 | if (!var.local() || var.isSpecial()) { | |
2333 | assignNode->bindings()->bindValue(generator, propertyName); | |
2334 | return; | |
2335 | } | |
2336 | generator.emitMove(var.local(), propertyName); | |
2337 | if (generator.vm()->typeProfiler()) | |
2338 | generator.emitTypeProfilerExpressionInfo(simpleBinding->divotStart(), simpleBinding->divotEnd()); | |
2339 | return; | |
81345200 | 2340 | } |
f9bf01c6 | 2341 | |
ed1e77d3 A |
2342 | RELEASE_ASSERT_NOT_REACHED(); |
2343 | } | |
2344 | ||
2345 | void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2346 | { | |
2347 | if (!m_lexpr->isAssignmentLocation()) { | |
2348 | emitThrowReferenceError(generator, ASCIILiteral("Left side of for-in statement is not a reference.")); | |
2349 | return; | |
2350 | } | |
f9bf01c6 | 2351 | |
ed1e77d3 | 2352 | RefPtr<Label> end = generator.newLabel(); |
f9bf01c6 | 2353 | |
81345200 | 2354 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
ed1e77d3 A |
2355 | |
2356 | RefPtr<RegisterID> base = generator.newTemporary(); | |
2357 | RefPtr<RegisterID> length; | |
2358 | RefPtr<RegisterID> enumerator; | |
2359 | generator.emitNode(base.get(), m_expr); | |
2360 | RefPtr<RegisterID> local = this->tryGetBoundLocal(generator); | |
2361 | RefPtr<RegisterID> enumeratorIndex; | |
2362 | ||
2363 | int profilerStartOffset = m_statement->startOffset(); | |
2364 | int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0); | |
2365 | ||
2366 | enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get()); | |
2367 | ||
2368 | // Indexed property loop. | |
2369 | { | |
2370 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); | |
2371 | RefPtr<Label> loopStart = generator.newLabel(); | |
2372 | RefPtr<Label> loopEnd = generator.newLabel(); | |
2373 | ||
2374 | length = generator.emitGetEnumerableLength(generator.newTemporary(), enumerator.get()); | |
2375 | RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0)); | |
2376 | RefPtr<RegisterID> propertyName = generator.newTemporary(); | |
2377 | ||
2378 | generator.emitLabel(loopStart.get()); | |
2379 | generator.emitLoopHint(); | |
2380 | ||
2381 | RefPtr<RegisterID> result = generator.emitEqualityOp(op_less, generator.newTemporary(), i.get(), length.get()); | |
2382 | generator.emitJumpIfFalse(result.get(), loopEnd.get()); | |
2383 | generator.emitHasIndexedProperty(result.get(), base.get(), i.get()); | |
2384 | generator.emitJumpIfFalse(result.get(), scope->continueTarget()); | |
2385 | ||
2386 | generator.emitToIndexString(propertyName.get(), i.get()); | |
2387 | this->emitLoopHeader(generator, propertyName.get()); | |
2388 | ||
2389 | generator.emitProfileControlFlow(profilerStartOffset); | |
2390 | ||
2391 | generator.pushIndexedForInScope(local.get(), i.get()); | |
2392 | generator.emitNode(dst, m_statement); | |
2393 | generator.popIndexedForInScope(local.get()); | |
2394 | ||
2395 | generator.emitProfileControlFlow(profilerEndOffset); | |
2396 | ||
2397 | generator.emitLabel(scope->continueTarget()); | |
2398 | generator.emitInc(i.get()); | |
2399 | generator.emitJump(loopStart.get()); | |
2400 | ||
2401 | generator.emitLabel(scope->breakTarget()); | |
2402 | generator.emitJump(end.get()); | |
2403 | generator.emitLabel(loopEnd.get()); | |
2404 | } | |
2405 | ||
2406 | // Structure property loop. | |
2407 | { | |
2408 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); | |
2409 | RefPtr<Label> loopStart = generator.newLabel(); | |
2410 | RefPtr<Label> loopEnd = generator.newLabel(); | |
2411 | ||
2412 | enumeratorIndex = generator.emitLoad(generator.newTemporary(), jsNumber(0)); | |
2413 | RefPtr<RegisterID> propertyName = generator.newTemporary(); | |
2414 | generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); | |
2415 | ||
2416 | generator.emitLabel(loopStart.get()); | |
2417 | generator.emitLoopHint(); | |
2418 | ||
2419 | RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get()); | |
2420 | generator.emitJumpIfTrue(result.get(), loopEnd.get()); | |
2421 | generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), enumerator.get()); | |
2422 | generator.emitJumpIfFalse(result.get(), scope->continueTarget()); | |
2423 | ||
2424 | this->emitLoopHeader(generator, propertyName.get()); | |
2425 | ||
2426 | generator.emitProfileControlFlow(profilerStartOffset); | |
2427 | ||
2428 | generator.pushStructureForInScope(local.get(), enumeratorIndex.get(), propertyName.get(), enumerator.get()); | |
2429 | generator.emitNode(dst, m_statement); | |
2430 | generator.popStructureForInScope(local.get()); | |
2431 | ||
2432 | generator.emitProfileControlFlow(profilerEndOffset); | |
2433 | ||
2434 | generator.emitLabel(scope->continueTarget()); | |
2435 | generator.emitInc(enumeratorIndex.get()); | |
2436 | generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); | |
2437 | generator.emitJump(loopStart.get()); | |
2438 | ||
2439 | generator.emitLabel(scope->breakTarget()); | |
2440 | generator.emitJump(end.get()); | |
2441 | generator.emitLabel(loopEnd.get()); | |
2442 | } | |
2443 | ||
2444 | // Generic property loop. | |
2445 | { | |
2446 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); | |
2447 | RefPtr<Label> loopStart = generator.newLabel(); | |
2448 | RefPtr<Label> loopEnd = generator.newLabel(); | |
2449 | ||
2450 | RefPtr<RegisterID> propertyName = generator.newTemporary(); | |
2451 | ||
2452 | generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); | |
2453 | ||
2454 | generator.emitLabel(loopStart.get()); | |
2455 | generator.emitLoopHint(); | |
2456 | ||
2457 | RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get()); | |
2458 | generator.emitJumpIfTrue(result.get(), loopEnd.get()); | |
2459 | ||
2460 | generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get()); | |
2461 | generator.emitJumpIfFalse(result.get(), scope->continueTarget()); | |
2462 | ||
2463 | this->emitLoopHeader(generator, propertyName.get()); | |
2464 | ||
2465 | generator.emitProfileControlFlow(profilerStartOffset); | |
2466 | ||
2467 | generator.emitNode(dst, m_statement); | |
2468 | ||
2469 | generator.emitLabel(scope->continueTarget()); | |
2470 | generator.emitInc(enumeratorIndex.get()); | |
2471 | generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); | |
2472 | generator.emitJump(loopStart.get()); | |
2473 | ||
2474 | generator.emitLabel(scope->breakTarget()); | |
2475 | generator.emitJump(end.get()); | |
2476 | generator.emitLabel(loopEnd.get()); | |
2477 | } | |
2478 | ||
2479 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); | |
2480 | generator.emitLabel(end.get()); | |
2481 | generator.emitProfileControlFlow(profilerEndOffset); | |
2482 | } | |
2483 | ||
2484 | void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2485 | { | |
2486 | this->emitMultiLoopBytecode(generator, dst); | |
f9bf01c6 A |
2487 | } |
2488 | ||
81345200 A |
2489 | // ------------------------------ ForOfNode ------------------------------------ |
2490 | void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2491 | { | |
2492 | if (!m_lexpr->isAssignmentLocation()) { | |
ed1e77d3 | 2493 | emitThrowReferenceError(generator, ASCIILiteral("Left side of for-of statement is not a reference.")); |
81345200 A |
2494 | return; |
2495 | } | |
ed1e77d3 | 2496 | |
81345200 A |
2497 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
2498 | auto extractor = [this, dst](BytecodeGenerator& generator, RegisterID* value) | |
2499 | { | |
2500 | if (m_lexpr->isResolveNode()) { | |
2501 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); | |
ed1e77d3 A |
2502 | Variable var = generator.variable(ident); |
2503 | if (RegisterID* local = var.local()) | |
2504 | generator.emitMove(local, value); | |
81345200 A |
2505 | else { |
2506 | if (generator.isStrictMode()) | |
2507 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); | |
ed1e77d3 | 2508 | RegisterID* scope = generator.emitResolveScope(nullptr, var); |
81345200 | 2509 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
ed1e77d3 A |
2510 | generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); |
2511 | if (generator.vm()->typeProfiler()) | |
2512 | generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); | |
81345200 | 2513 | } |
ed1e77d3 A |
2514 | if (generator.vm()->typeProfiler()) |
2515 | generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); | |
81345200 A |
2516 | } else if (m_lexpr->isDotAccessorNode()) { |
2517 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); | |
2518 | const Identifier& ident = assignNode->identifier(); | |
2519 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); | |
2520 | ||
2521 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); | |
2522 | generator.emitPutById(base.get(), ident, value); | |
ed1e77d3 A |
2523 | if (generator.vm()->typeProfiler()) { |
2524 | generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
2525 | generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); | |
2526 | } | |
81345200 A |
2527 | } else if (m_lexpr->isBracketAccessorNode()) { |
2528 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); | |
2529 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); | |
2530 | RegisterID* subscript = generator.emitNode(assignNode->subscript()); | |
2531 | ||
2532 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); | |
2533 | generator.emitPutByVal(base.get(), subscript, value); | |
ed1e77d3 A |
2534 | if (generator.vm()->typeProfiler()) { |
2535 | generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); | |
2536 | generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); | |
2537 | } | |
81345200 | 2538 | } else { |
ed1e77d3 A |
2539 | ASSERT(m_lexpr->isDestructuringNode()); |
2540 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); | |
81345200 A |
2541 | assignNode->bindings()->bindValue(generator, value); |
2542 | } | |
ed1e77d3 | 2543 | generator.emitProfileControlFlow(m_statement->startOffset()); |
81345200 A |
2544 | generator.emitNode(dst, m_statement); |
2545 | }; | |
2546 | generator.emitEnumeration(this, m_expr, extractor); | |
ed1e77d3 | 2547 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); |
81345200 A |
2548 | } |
2549 | ||
f9bf01c6 A |
2550 | // ------------------------------ ContinueNode --------------------------------- |
2551 | ||
93a37866 A |
2552 | Label* ContinueNode::trivialTarget(BytecodeGenerator& generator) |
2553 | { | |
2554 | if (generator.shouldEmitDebugHooks()) | |
2555 | return 0; | |
2556 | ||
81345200 | 2557 | LabelScopePtr scope = generator.continueTarget(m_ident); |
93a37866 A |
2558 | ASSERT(scope); |
2559 | ||
2560 | if (generator.scopeDepth() != scope->scopeDepth()) | |
2561 | return 0; | |
2562 | ||
2563 | return scope->continueTarget(); | |
2564 | } | |
2565 | ||
2566 | void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
f9bf01c6 | 2567 | { |
81345200 | 2568 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2569 | |
81345200 | 2570 | LabelScopePtr scope = generator.continueTarget(m_ident); |
14957cd0 | 2571 | ASSERT(scope); |
f9bf01c6 | 2572 | |
ed1e77d3 | 2573 | generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth()); |
93a37866 | 2574 | generator.emitJump(scope->continueTarget()); |
ed1e77d3 A |
2575 | |
2576 | generator.emitProfileControlFlow(endOffset()); | |
f9bf01c6 A |
2577 | } |
2578 | ||
2579 | // ------------------------------ BreakNode ------------------------------------ | |
2580 | ||
93a37866 | 2581 | Label* BreakNode::trivialTarget(BytecodeGenerator& generator) |
f9bf01c6 | 2582 | { |
93a37866 A |
2583 | if (generator.shouldEmitDebugHooks()) |
2584 | return 0; | |
2585 | ||
81345200 | 2586 | LabelScopePtr scope = generator.breakTarget(m_ident); |
93a37866 A |
2587 | ASSERT(scope); |
2588 | ||
2589 | if (generator.scopeDepth() != scope->scopeDepth()) | |
2590 | return 0; | |
2591 | ||
2592 | return scope->breakTarget(); | |
2593 | } | |
2594 | ||
2595 | void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
2596 | { | |
81345200 | 2597 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2598 | |
81345200 | 2599 | LabelScopePtr scope = generator.breakTarget(m_ident); |
14957cd0 | 2600 | ASSERT(scope); |
f9bf01c6 | 2601 | |
ed1e77d3 | 2602 | generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth()); |
93a37866 | 2603 | generator.emitJump(scope->breakTarget()); |
ed1e77d3 A |
2604 | |
2605 | generator.emitProfileControlFlow(endOffset()); | |
f9bf01c6 A |
2606 | } |
2607 | ||
2608 | // ------------------------------ ReturnNode ----------------------------------- | |
2609 | ||
93a37866 | 2610 | void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2611 | { |
81345200 | 2612 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
14957cd0 | 2613 | ASSERT(generator.codeType() == FunctionCode); |
f9bf01c6 A |
2614 | |
2615 | if (dst == generator.ignoredResult()) | |
2616 | dst = 0; | |
93a37866 A |
2617 | |
2618 | RefPtr<RegisterID> returnRegister = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); | |
ed1e77d3 A |
2619 | if (generator.vm()->typeProfiler()) { |
2620 | generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, nullptr); | |
2621 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
2622 | } | |
f9bf01c6 | 2623 | if (generator.scopeDepth()) { |
93a37866 | 2624 | returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get()); |
ed1e77d3 | 2625 | generator.emitPopScopes(generator.scopeRegister(), 0); |
f9bf01c6 | 2626 | } |
93a37866 | 2627 | |
81345200 | 2628 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); |
93a37866 | 2629 | generator.emitReturn(returnRegister.get()); |
ed1e77d3 A |
2630 | generator.emitProfileControlFlow(endOffset()); |
2631 | // Emitting an unreachable return here is needed in case this op_profile_control_flow is the | |
2632 | // last opcode in a CodeBlock because a CodeBlock's instructions must end with a terminal opcode. | |
2633 | if (generator.vm()->controlFlowProfiler()) | |
2634 | generator.emitReturn(generator.emitLoad(nullptr, jsUndefined())); | |
f9bf01c6 A |
2635 | } |
2636 | ||
2637 | // ------------------------------ WithNode ------------------------------------- | |
2638 | ||
93a37866 | 2639 | void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2640 | { |
81345200 | 2641 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 A |
2642 | |
2643 | RefPtr<RegisterID> scope = generator.emitNode(m_expr); | |
81345200 | 2644 | generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot); |
ed1e77d3 | 2645 | generator.emitPushWithScope(generator.scopeRegister(), scope.get()); |
93a37866 | 2646 | generator.emitNode(dst, m_statement); |
ed1e77d3 | 2647 | generator.emitPopScope(generator.scopeRegister()); |
f9bf01c6 A |
2648 | } |
2649 | ||
2650 | // ------------------------------ CaseClauseNode -------------------------------- | |
2651 | ||
2652 | inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2653 | { | |
ed1e77d3 | 2654 | generator.emitProfileControlFlow(m_startOffset); |
93a37866 A |
2655 | if (!m_statements) |
2656 | return; | |
2657 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
2658 | } |
2659 | ||
2660 | // ------------------------------ CaseBlockNode -------------------------------- | |
2661 | ||
2662 | enum SwitchKind { | |
2663 | SwitchUnset = 0, | |
2664 | SwitchNumber = 1, | |
2665 | SwitchString = 2, | |
2666 | SwitchNeither = 3 | |
2667 | }; | |
2668 | ||
2669 | static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) | |
2670 | { | |
2671 | for (; list; list = list->getNext()) { | |
2672 | ExpressionNode* clauseExpression = list->getClause()->expr(); | |
2673 | literalVector.append(clauseExpression); | |
2674 | if (clauseExpression->isNumber()) { | |
2675 | double value = static_cast<NumberNode*>(clauseExpression)->value(); | |
2676 | int32_t intVal = static_cast<int32_t>(value); | |
2677 | if ((typeForTable & ~SwitchNumber) || (intVal != value)) { | |
2678 | typeForTable = SwitchNeither; | |
2679 | break; | |
2680 | } | |
2681 | if (intVal < min_num) | |
2682 | min_num = intVal; | |
2683 | if (intVal > max_num) | |
2684 | max_num = intVal; | |
2685 | typeForTable = SwitchNumber; | |
2686 | continue; | |
2687 | } | |
2688 | if (clauseExpression->isString()) { | |
2689 | if (typeForTable & ~SwitchString) { | |
2690 | typeForTable = SwitchNeither; | |
2691 | break; | |
2692 | } | |
93a37866 | 2693 | const String& value = static_cast<StringNode*>(clauseExpression)->value().string(); |
14957cd0 | 2694 | if (singleCharacterSwitch &= value.length() == 1) { |
6fe7ccc8 | 2695 | int32_t intVal = value[0]; |
f9bf01c6 A |
2696 | if (intVal < min_num) |
2697 | min_num = intVal; | |
2698 | if (intVal > max_num) | |
2699 | max_num = intVal; | |
2700 | } | |
2701 | typeForTable = SwitchString; | |
2702 | continue; | |
2703 | } | |
2704 | typeForTable = SwitchNeither; | |
2705 | break; | |
2706 | } | |
2707 | } | |
93a37866 A |
2708 | |
2709 | static inline size_t length(ClauseListNode* list1, ClauseListNode* list2) | |
f9bf01c6 | 2710 | { |
93a37866 A |
2711 | size_t length = 0; |
2712 | for (ClauseListNode* node = list1; node; node = node->getNext()) | |
2713 | ++length; | |
2714 | for (ClauseListNode* node = list2; node; node = node->getNext()) | |
2715 | ++length; | |
2716 | return length; | |
2717 | } | |
2718 | ||
2719 | SwitchInfo::SwitchType CaseBlockNode::tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) | |
2720 | { | |
2721 | if (length(m_list1, m_list2) < s_tableSwitchMinimum) | |
2722 | return SwitchInfo::SwitchNone; | |
2723 | ||
f9bf01c6 A |
2724 | SwitchKind typeForTable = SwitchUnset; |
2725 | bool singleCharacterSwitch = true; | |
2726 | ||
2727 | processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); | |
2728 | processClauseList(m_list2, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); | |
2729 | ||
2730 | if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) | |
2731 | return SwitchInfo::SwitchNone; | |
2732 | ||
2733 | if (typeForTable == SwitchNumber) { | |
2734 | int32_t range = max_num - min_num; | |
2735 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) | |
2736 | return SwitchInfo::SwitchImmediate; | |
2737 | return SwitchInfo::SwitchNone; | |
2738 | } | |
2739 | ||
2740 | ASSERT(typeForTable == SwitchString); | |
2741 | ||
2742 | if (singleCharacterSwitch) { | |
2743 | int32_t range = max_num - min_num; | |
2744 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) | |
2745 | return SwitchInfo::SwitchCharacter; | |
2746 | } | |
2747 | ||
2748 | return SwitchInfo::SwitchString; | |
2749 | } | |
2750 | ||
93a37866 | 2751 | void CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) |
f9bf01c6 A |
2752 | { |
2753 | RefPtr<Label> defaultLabel; | |
2754 | Vector<RefPtr<Label>, 8> labelVector; | |
2755 | Vector<ExpressionNode*, 8> literalVector; | |
2756 | int32_t min_num = std::numeric_limits<int32_t>::max(); | |
2757 | int32_t max_num = std::numeric_limits<int32_t>::min(); | |
93a37866 | 2758 | SwitchInfo::SwitchType switchType = tryTableSwitch(literalVector, min_num, max_num); |
f9bf01c6 A |
2759 | |
2760 | if (switchType != SwitchInfo::SwitchNone) { | |
2761 | // Prepare the various labels | |
2762 | for (uint32_t i = 0; i < literalVector.size(); i++) | |
2763 | labelVector.append(generator.newLabel()); | |
2764 | defaultLabel = generator.newLabel(); | |
2765 | generator.beginSwitch(switchExpression, switchType); | |
2766 | } else { | |
2767 | // Setup jumps | |
2768 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { | |
2769 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); | |
2770 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); | |
2771 | generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); | |
2772 | labelVector.append(generator.newLabel()); | |
2773 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); | |
2774 | } | |
2775 | ||
2776 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { | |
2777 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); | |
2778 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); | |
2779 | generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); | |
2780 | labelVector.append(generator.newLabel()); | |
2781 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); | |
2782 | } | |
2783 | defaultLabel = generator.newLabel(); | |
2784 | generator.emitJump(defaultLabel.get()); | |
2785 | } | |
2786 | ||
f9bf01c6 A |
2787 | size_t i = 0; |
2788 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { | |
2789 | generator.emitLabel(labelVector[i++].get()); | |
2790 | list->getClause()->emitBytecode(generator, dst); | |
2791 | } | |
2792 | ||
2793 | if (m_defaultClause) { | |
2794 | generator.emitLabel(defaultLabel.get()); | |
2795 | m_defaultClause->emitBytecode(generator, dst); | |
2796 | } | |
2797 | ||
2798 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { | |
2799 | generator.emitLabel(labelVector[i++].get()); | |
2800 | list->getClause()->emitBytecode(generator, dst); | |
2801 | } | |
2802 | if (!m_defaultClause) | |
2803 | generator.emitLabel(defaultLabel.get()); | |
2804 | ||
2805 | ASSERT(i == labelVector.size()); | |
2806 | if (switchType != SwitchInfo::SwitchNone) { | |
2807 | ASSERT(labelVector.size() == literalVector.size()); | |
2808 | generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); | |
2809 | } | |
f9bf01c6 A |
2810 | } |
2811 | ||
2812 | // ------------------------------ SwitchNode ----------------------------------- | |
2813 | ||
93a37866 | 2814 | void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2815 | { |
81345200 | 2816 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2817 | |
93a37866 | 2818 | LabelScopePtr scope = generator.newLabelScope(LabelScope::Switch); |
f9bf01c6 A |
2819 | |
2820 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); | |
93a37866 | 2821 | m_block->emitBytecodeForBlock(generator, r0.get(), dst); |
f9bf01c6 A |
2822 | |
2823 | generator.emitLabel(scope->breakTarget()); | |
ed1e77d3 | 2824 | generator.emitProfileControlFlow(endOffset()); |
f9bf01c6 A |
2825 | } |
2826 | ||
2827 | // ------------------------------ LabelNode ------------------------------------ | |
2828 | ||
93a37866 | 2829 | void LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2830 | { |
81345200 | 2831 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2832 | |
14957cd0 | 2833 | ASSERT(!generator.breakTarget(m_name)); |
f9bf01c6 | 2834 | |
93a37866 A |
2835 | LabelScopePtr scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); |
2836 | generator.emitNode(dst, m_statement); | |
f9bf01c6 A |
2837 | |
2838 | generator.emitLabel(scope->breakTarget()); | |
f9bf01c6 A |
2839 | } |
2840 | ||
2841 | // ------------------------------ ThrowNode ------------------------------------ | |
2842 | ||
93a37866 | 2843 | void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 | 2844 | { |
81345200 | 2845 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
f9bf01c6 A |
2846 | |
2847 | if (dst == generator.ignoredResult()) | |
2848 | dst = 0; | |
2849 | RefPtr<RegisterID> expr = generator.emitNode(m_expr); | |
81345200 | 2850 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
f9bf01c6 | 2851 | generator.emitThrow(expr.get()); |
ed1e77d3 A |
2852 | |
2853 | generator.emitProfileControlFlow(endOffset()); | |
f9bf01c6 A |
2854 | } |
2855 | ||
2856 | // ------------------------------ TryNode -------------------------------------- | |
2857 | ||
93a37866 | 2858 | void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
f9bf01c6 A |
2859 | { |
2860 | // NOTE: The catch and finally blocks must be labeled explicitly, so the | |
2861 | // optimizer knows they may be jumped to from anywhere. | |
2862 | ||
81345200 | 2863 | generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); |
93a37866 A |
2864 | |
2865 | ASSERT(m_catchBlock || m_finallyBlock); | |
f9bf01c6 A |
2866 | |
2867 | RefPtr<Label> tryStartLabel = generator.newLabel(); | |
93a37866 A |
2868 | generator.emitLabel(tryStartLabel.get()); |
2869 | ||
6fe7ccc8 A |
2870 | if (m_finallyBlock) |
2871 | generator.pushFinallyContext(m_finallyBlock); | |
93a37866 | 2872 | TryData* tryData = generator.pushTry(tryStartLabel.get()); |
f9bf01c6 | 2873 | |
f9bf01c6 A |
2874 | generator.emitNode(dst, m_tryBlock); |
2875 | ||
2876 | if (m_catchBlock) { | |
2877 | RefPtr<Label> catchEndLabel = generator.newLabel(); | |
2878 | ||
2879 | // Normal path: jump over the catch block. | |
2880 | generator.emitJump(catchEndLabel.get()); | |
2881 | ||
2882 | // Uncaught exception path: the catch block. | |
2883 | RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); | |
ed1e77d3 A |
2884 | RefPtr<RegisterID> exceptionRegister = generator.newTemporary(); |
2885 | RefPtr<RegisterID> thrownValueRegister = generator.newTemporary(); | |
2886 | generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), here.get(), HandlerType::Catch); | |
93a37866 A |
2887 | |
2888 | if (m_finallyBlock) { | |
2889 | // If the catch block throws an exception and we have a finally block, then the finally | |
2890 | // block should "catch" that exception. | |
2891 | tryData = generator.pushTry(here.get()); | |
2892 | } | |
ed1e77d3 A |
2893 | |
2894 | generator.emitPushCatchScope(generator.scopeRegister(), m_thrownValueIdent, thrownValueRegister.get(), DontDelete); | |
2895 | generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1); | |
f9bf01c6 | 2896 | generator.emitNode(dst, m_catchBlock); |
ed1e77d3 | 2897 | generator.emitPopScope(generator.scopeRegister()); |
f9bf01c6 A |
2898 | generator.emitLabel(catchEndLabel.get()); |
2899 | } | |
2900 | ||
2901 | if (m_finallyBlock) { | |
93a37866 A |
2902 | RefPtr<Label> preFinallyLabel = generator.emitLabel(generator.newLabel().get()); |
2903 | ||
f9bf01c6 | 2904 | generator.popFinallyContext(); |
6fe7ccc8 | 2905 | |
f9bf01c6 A |
2906 | RefPtr<Label> finallyEndLabel = generator.newLabel(); |
2907 | ||
ed1e77d3 A |
2908 | int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1; |
2909 | ||
6fe7ccc8 | 2910 | // Normal path: run the finally code, and jump to the end. |
ed1e77d3 | 2911 | generator.emitProfileControlFlow(finallyStartOffset); |
6fe7ccc8 | 2912 | generator.emitNode(dst, m_finallyBlock); |
ed1e77d3 | 2913 | generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1); |
f9bf01c6 A |
2914 | generator.emitJump(finallyEndLabel.get()); |
2915 | ||
2916 | // Uncaught exception path: invoke the finally block, then re-throw the exception. | |
ed1e77d3 A |
2917 | RefPtr<RegisterID> exceptionRegister = generator.newTemporary(); |
2918 | RefPtr<RegisterID> thrownValueRegister = generator.newTemporary(); | |
2919 | generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), preFinallyLabel.get(), HandlerType::Finally); | |
2920 | generator.emitProfileControlFlow(finallyStartOffset); | |
f9bf01c6 | 2921 | generator.emitNode(dst, m_finallyBlock); |
ed1e77d3 | 2922 | generator.emitThrow(exceptionRegister.get()); |
f9bf01c6 A |
2923 | |
2924 | generator.emitLabel(finallyEndLabel.get()); | |
ed1e77d3 A |
2925 | generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1); |
2926 | } else | |
2927 | generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1); | |
2928 | ||
f9bf01c6 A |
2929 | } |
2930 | ||
2931 | // ------------------------------ ScopeNode ----------------------------- | |
2932 | ||
2933 | inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
2934 | { | |
93a37866 A |
2935 | if (!m_statements) |
2936 | return; | |
2937 | m_statements->emitBytecode(generator, dst); | |
f9bf01c6 A |
2938 | } |
2939 | ||
2940 | // ------------------------------ ProgramNode ----------------------------- | |
2941 | ||
93a37866 | 2942 | void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2943 | { |
81345200 | 2944 | generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 A |
2945 | |
2946 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); | |
2947 | generator.emitLoad(dstRegister.get(), jsUndefined()); | |
ed1e77d3 | 2948 | generator.emitProfileControlFlow(startStartOffset()); |
f9bf01c6 A |
2949 | emitStatementsBytecode(generator, dstRegister.get()); |
2950 | ||
81345200 | 2951 | generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2952 | generator.emitEnd(dstRegister.get()); |
f9bf01c6 A |
2953 | } |
2954 | ||
2955 | // ------------------------------ EvalNode ----------------------------- | |
2956 | ||
93a37866 | 2957 | void EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
f9bf01c6 | 2958 | { |
81345200 | 2959 | generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 A |
2960 | |
2961 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); | |
2962 | generator.emitLoad(dstRegister.get(), jsUndefined()); | |
2963 | emitStatementsBytecode(generator, dstRegister.get()); | |
2964 | ||
81345200 | 2965 | generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); |
f9bf01c6 | 2966 | generator.emitEnd(dstRegister.get()); |
f9bf01c6 A |
2967 | } |
2968 | ||
2969 | // ------------------------------ FunctionBodyNode ----------------------------- | |
2970 | ||
ed1e77d3 | 2971 | void FunctionBodyNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
f9bf01c6 | 2972 | { |
ed1e77d3 A |
2973 | } |
2974 | ||
2975 | void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) | |
2976 | { | |
2977 | if (generator.vm()->typeProfiler()) { | |
2978 | for (size_t i = 0; i < m_parameters->size(); i++) { | |
2979 | // FIXME: Handle Destructuring assignments into arguments. | |
2980 | if (!m_parameters->at(i)->isBindingNode()) | |
2981 | continue; | |
2982 | BindingNode* parameter = static_cast<BindingNode*>(m_parameters->at(i)); | |
2983 | RegisterID reg(CallFrame::argumentOffset(i)); | |
2984 | generator.emitProfileType(®, ProfileTypeBytecodeFunctionArgument, nullptr); | |
2985 | generator.emitTypeProfilerExpressionInfo(parameter->divotStart(), parameter->divotEnd()); | |
2986 | } | |
2987 | } | |
2988 | ||
2989 | generator.emitProfileControlFlow(startStartOffset()); | |
81345200 | 2990 | generator.emitDebugHook(DidEnterCallFrame, startLine(), startStartOffset(), startLineStartOffset()); |
f9bf01c6 | 2991 | emitStatementsBytecode(generator, generator.ignoredResult()); |
14957cd0 | 2992 | |
f9bf01c6 | 2993 | StatementNode* singleStatement = this->singleStatement(); |
14957cd0 A |
2994 | ReturnNode* returnNode = 0; |
2995 | ||
2996 | // Check for a return statement at the end of a function composed of a single block. | |
f9bf01c6 A |
2997 | if (singleStatement && singleStatement->isBlock()) { |
2998 | StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); | |
2999 | if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) | |
14957cd0 A |
3000 | returnNode = static_cast<ReturnNode*>(lastStatementInBlock); |
3001 | } | |
3002 | ||
3003 | // If there is no return we must automatically insert one. | |
3004 | if (!returnNode) { | |
3005 | RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); | |
ed1e77d3 A |
3006 | if (generator.vm()->typeProfiler()) |
3007 | generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement, nullptr); // Do not emit expression info for this profile because it's not in the user's source code. | |
81345200 A |
3008 | ASSERT(startOffset() >= lineStartOffset()); |
3009 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); | |
14957cd0 | 3010 | generator.emitReturn(r0); |
93a37866 | 3011 | return; |
14957cd0 | 3012 | } |
f9bf01c6 A |
3013 | } |
3014 | ||
3015 | // ------------------------------ FuncDeclNode --------------------------------- | |
3016 | ||
93a37866 | 3017 | void FuncDeclNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
f9bf01c6 | 3018 | { |
f9bf01c6 A |
3019 | } |
3020 | ||
3021 | // ------------------------------ FuncExprNode --------------------------------- | |
3022 | ||
3023 | RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
3024 | { | |
3025 | return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); | |
3026 | } | |
ed1e77d3 A |
3027 | |
3028 | #if ENABLE(ES6_CLASS_SYNTAX) | |
3029 | // ------------------------------ ClassDeclNode --------------------------------- | |
3030 | ||
3031 | void ClassDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
3032 | { | |
3033 | generator.emitNode(dst, m_classDeclaration); | |
3034 | } | |
3035 | ||
3036 | // ------------------------------ ClassExprNode --------------------------------- | |
3037 | ||
3038 | RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
3039 | { | |
3040 | RefPtr<RegisterID> superclass; | |
3041 | if (m_classHeritage) { | |
3042 | superclass = generator.newTemporary(); | |
3043 | generator.emitNode(superclass.get(), m_classHeritage); | |
3044 | } | |
3045 | ||
3046 | RefPtr<RegisterID> constructor; | |
3047 | ||
3048 | // FIXME: Make the prototype non-configurable & non-writable. | |
3049 | if (m_constructorExpression) | |
3050 | constructor = generator.emitNode(dst, m_constructorExpression); | |
3051 | else { | |
3052 | constructor = generator.emitNewDefaultConstructor(generator.finalDestination(dst), | |
3053 | m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base, m_name); | |
3054 | } | |
3055 | ||
3056 | const auto& propertyNames = generator.propertyNames(); | |
3057 | RefPtr<RegisterID> prototype = generator.emitNewObject(generator.newTemporary()); | |
3058 | ||
3059 | if (superclass) { | |
3060 | RefPtr<RegisterID> protoParent = generator.newTemporary(); | |
3061 | generator.emitLoad(protoParent.get(), jsNull()); | |
3062 | ||
3063 | RefPtr<RegisterID> tempRegister = generator.newTemporary(); | |
3064 | ||
3065 | // FIXME: Throw TypeError if it's a generator function. | |
3066 | RefPtr<Label> superclassIsUndefinedLabel = generator.newLabel(); | |
3067 | generator.emitJumpIfTrue(generator.emitIsUndefined(tempRegister.get(), superclass.get()), superclassIsUndefinedLabel.get()); | |
3068 | ||
3069 | RefPtr<Label> superclassIsNullLabel = generator.newLabel(); | |
3070 | generator.emitJumpIfTrue(generator.emitUnaryOp(op_eq_null, tempRegister.get(), superclass.get()), superclassIsNullLabel.get()); | |
3071 | ||
3072 | RefPtr<Label> superclassIsObjectLabel = generator.newLabel(); | |
3073 | generator.emitJumpIfTrue(generator.emitIsObject(tempRegister.get(), superclass.get()), superclassIsObjectLabel.get()); | |
3074 | generator.emitLabel(superclassIsUndefinedLabel.get()); | |
3075 | generator.emitThrowTypeError(ASCIILiteral("The superclass is not an object.")); | |
3076 | generator.emitLabel(superclassIsObjectLabel.get()); | |
3077 | generator.emitGetById(protoParent.get(), superclass.get(), generator.propertyNames().prototype); | |
3078 | ||
3079 | RefPtr<Label> protoParentIsObjectOrNullLabel = generator.newLabel(); | |
3080 | generator.emitJumpIfTrue(generator.emitUnaryOp(op_is_object_or_null, tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get()); | |
3081 | generator.emitThrowTypeError(ASCIILiteral("The superclass's prototype is not an object.")); | |
3082 | generator.emitLabel(protoParentIsObjectOrNullLabel.get()); | |
3083 | ||
3084 | generator.emitDirectPutById(constructor.get(), generator.propertyNames().underscoreProto, superclass.get(), PropertyNode::Unknown); | |
3085 | generator.emitLabel(superclassIsNullLabel.get()); | |
3086 | generator.emitDirectPutById(prototype.get(), generator.propertyNames().underscoreProto, protoParent.get(), PropertyNode::Unknown); | |
3087 | ||
3088 | emitPutHomeObject(generator, constructor.get(), prototype.get()); | |
3089 | } | |
3090 | ||
3091 | RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.constructor); | |
3092 | generator.emitCallDefineProperty(prototype.get(), constructorNameRegister.get(), constructor.get(), nullptr, nullptr, | |
3093 | BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); | |
3094 | ||
3095 | RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.prototype); | |
3096 | generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position); | |
3097 | ||
3098 | if (m_staticMethods) | |
3099 | generator.emitNode(constructor.get(), m_staticMethods); | |
3100 | ||
3101 | if (m_instanceMethods) | |
3102 | generator.emitNode(prototype.get(), m_instanceMethods); | |
3103 | ||
3104 | return generator.moveToDestinationIfNeeded(dst, constructor.get()); | |
3105 | } | |
3106 | #endif | |
81345200 | 3107 | |
ed1e77d3 A |
3108 | // ------------------------------ DestructuringAssignmentNode ----------------- |
3109 | RegisterID* DestructuringAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) | |
81345200 A |
3110 | { |
3111 | if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer)) | |
3112 | return result; | |
3113 | RefPtr<RegisterID> initializer = generator.tempDestination(dst); | |
3114 | generator.emitNode(initializer.get(), m_initializer); | |
3115 | m_bindings->bindValue(generator, initializer.get()); | |
3116 | return generator.moveToDestinationIfNeeded(dst, initializer.get()); | |
3117 | } | |
3118 | ||
ed1e77d3 | 3119 | DestructuringPatternNode::~DestructuringPatternNode() |
81345200 A |
3120 | { |
3121 | } | |
ed1e77d3 A |
3122 | |
3123 | static void assignDefaultValueIfUndefined(BytecodeGenerator& generator, RegisterID* maybeUndefined, ExpressionNode* defaultValue) | |
3124 | { | |
3125 | ASSERT(defaultValue); | |
3126 | RefPtr<Label> isNotUndefined = generator.newLabel(); | |
3127 | generator.emitJumpIfFalse(generator.emitIsUndefined(generator.newTemporary(), maybeUndefined), isNotUndefined.get()); | |
3128 | generator.emitNode(maybeUndefined, defaultValue); | |
3129 | generator.emitLabel(isNotUndefined.get()); | |
3130 | } | |
3131 | ||
81345200 A |
3132 | void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const |
3133 | { | |
ed1e77d3 A |
3134 | RefPtr<RegisterID> iterator = generator.newTemporary(); |
3135 | { | |
3136 | generator.emitGetById(iterator.get(), rhs, generator.propertyNames().iteratorSymbol); | |
3137 | CallArguments args(generator, nullptr); | |
3138 | generator.emitMove(args.thisRegister(), rhs); | |
3139 | generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd()); | |
3140 | } | |
3141 | ||
3142 | if (m_targetPatterns.isEmpty()) { | |
3143 | generator.emitIteratorClose(iterator.get(), this); | |
3144 | return; | |
3145 | } | |
3146 | ||
3147 | RefPtr<RegisterID> done; | |
3148 | for (auto& target : m_targetPatterns) { | |
3149 | switch (target.bindingType) { | |
3150 | case BindingType::Elision: | |
3151 | case BindingType::Element: { | |
3152 | RefPtr<Label> iterationSkipped = generator.newLabel(); | |
3153 | if (!done) | |
3154 | done = generator.newTemporary(); | |
3155 | else | |
3156 | generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); | |
3157 | ||
3158 | RefPtr<RegisterID> value = generator.newTemporary(); | |
3159 | generator.emitIteratorNext(value.get(), iterator.get(), this); | |
3160 | generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); | |
3161 | generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); | |
3162 | generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); | |
3163 | ||
3164 | { | |
3165 | RefPtr<Label> valueIsSet = generator.newLabel(); | |
3166 | generator.emitJump(valueIsSet.get()); | |
3167 | generator.emitLabel(iterationSkipped.get()); | |
3168 | generator.emitLoad(value.get(), jsUndefined()); | |
3169 | generator.emitLabel(valueIsSet.get()); | |
3170 | } | |
3171 | ||
3172 | if (target.bindingType == BindingType::Element) { | |
3173 | if (target.defaultValue) | |
3174 | assignDefaultValueIfUndefined(generator, value.get(), target.defaultValue); | |
3175 | target.pattern->bindValue(generator, value.get()); | |
3176 | } | |
3177 | break; | |
3178 | } | |
3179 | ||
3180 | case BindingType::RestElement: { | |
3181 | RefPtr<RegisterID> array = generator.emitNewArray(generator.newTemporary(), 0, 0); | |
3182 | ||
3183 | RefPtr<Label> iterationDone = generator.newLabel(); | |
3184 | if (!done) | |
3185 | done = generator.newTemporary(); | |
3186 | else | |
3187 | generator.emitJumpIfTrue(done.get(), iterationDone.get()); | |
3188 | ||
3189 | RefPtr<RegisterID> index = generator.newTemporary(); | |
3190 | generator.emitLoad(index.get(), jsNumber(0)); | |
3191 | RefPtr<Label> loopStart = generator.newLabel(); | |
3192 | generator.emitLabel(loopStart.get()); | |
3193 | ||
3194 | RefPtr<RegisterID> value = generator.newTemporary(); | |
3195 | generator.emitIteratorNext(value.get(), iterator.get(), this); | |
3196 | generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); | |
3197 | generator.emitJumpIfTrue(done.get(), iterationDone.get()); | |
3198 | generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); | |
3199 | ||
3200 | generator.emitDirectPutByVal(array.get(), index.get(), value.get()); | |
3201 | generator.emitInc(index.get()); | |
3202 | generator.emitJump(loopStart.get()); | |
3203 | ||
3204 | generator.emitLabel(iterationDone.get()); | |
3205 | target.pattern->bindValue(generator, array.get()); | |
3206 | break; | |
3207 | } | |
3208 | } | |
81345200 | 3209 | } |
ed1e77d3 A |
3210 | |
3211 | RefPtr<Label> iteratorClosed = generator.newLabel(); | |
3212 | generator.emitJumpIfTrue(done.get(), iteratorClosed.get()); | |
3213 | generator.emitIteratorClose(iterator.get(), this); | |
3214 | generator.emitLabel(iteratorClosed.get()); | |
81345200 A |
3215 | } |
3216 | ||
3217 | RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs) | |
3218 | { | |
81345200 A |
3219 | if (!rhs->isSimpleArray()) |
3220 | return 0; | |
3221 | ||
3222 | RefPtr<RegisterID> resultRegister; | |
3223 | if (dst && dst != generator.ignoredResult()) | |
3224 | resultRegister = generator.emitNewArray(generator.newTemporary(), 0, 0); | |
3225 | ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements(); | |
3226 | Vector<ExpressionNode*> elements; | |
3227 | for (; elementNodes; elementNodes = elementNodes->next()) | |
3228 | elements.append(elementNodes->value()); | |
3229 | if (m_targetPatterns.size() != elements.size()) | |
3230 | return 0; | |
3231 | Vector<RefPtr<RegisterID>> registers; | |
3232 | registers.reserveCapacity(m_targetPatterns.size()); | |
3233 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
3234 | registers.uncheckedAppend(generator.newTemporary()); | |
3235 | generator.emitNode(registers.last().get(), elements[i]); | |
ed1e77d3 A |
3236 | if (m_targetPatterns[i].defaultValue) |
3237 | assignDefaultValueIfUndefined(generator, registers.last().get(), m_targetPatterns[i].defaultValue); | |
81345200 A |
3238 | if (resultRegister) |
3239 | generator.emitPutByIndex(resultRegister.get(), i, registers.last().get()); | |
3240 | } | |
3241 | ||
3242 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
ed1e77d3 A |
3243 | if (m_targetPatterns[i].pattern) |
3244 | m_targetPatterns[i].pattern->bindValue(generator, registers[i].get()); | |
81345200 A |
3245 | } |
3246 | if (resultRegister) | |
3247 | return generator.moveToDestinationIfNeeded(dst, resultRegister.get()); | |
3248 | return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); | |
3249 | } | |
3250 | ||
3251 | void ArrayPatternNode::toString(StringBuilder& builder) const | |
3252 | { | |
3253 | builder.append('['); | |
3254 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
ed1e77d3 A |
3255 | const auto& target = m_targetPatterns[i]; |
3256 | ||
3257 | switch (target.bindingType) { | |
3258 | case BindingType::Elision: | |
81345200 | 3259 | builder.append(','); |
ed1e77d3 A |
3260 | break; |
3261 | ||
3262 | case BindingType::Element: | |
3263 | target.pattern->toString(builder); | |
3264 | if (i < m_targetPatterns.size() - 1) | |
3265 | builder.append(','); | |
3266 | break; | |
3267 | ||
3268 | case BindingType::RestElement: | |
3269 | builder.append("..."); | |
3270 | target.pattern->toString(builder); | |
3271 | break; | |
81345200 | 3272 | } |
81345200 A |
3273 | } |
3274 | builder.append(']'); | |
3275 | } | |
3276 | ||
3277 | void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
3278 | { | |
3279 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
ed1e77d3 | 3280 | if (DestructuringPatternNode* node = m_targetPatterns[i].pattern.get()) |
81345200 A |
3281 | node->collectBoundIdentifiers(identifiers); |
3282 | } | |
3283 | } | |
3284 | ||
3285 | void ObjectPatternNode::toString(StringBuilder& builder) const | |
3286 | { | |
3287 | builder.append('{'); | |
3288 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
ed1e77d3 A |
3289 | if (m_targetPatterns[i].wasString) |
3290 | builder.appendQuotedJSONString(m_targetPatterns[i].propertyName.string()); | |
3291 | else | |
81345200 | 3292 | builder.append(m_targetPatterns[i].propertyName.string()); |
ed1e77d3 | 3293 | builder.append(':'); |
81345200 A |
3294 | m_targetPatterns[i].pattern->toString(builder); |
3295 | if (i < m_targetPatterns.size() - 1) | |
3296 | builder.append(','); | |
3297 | } | |
3298 | builder.append('}'); | |
3299 | } | |
3300 | ||
3301 | void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const | |
3302 | { | |
3303 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { | |
3304 | auto& target = m_targetPatterns[i]; | |
3305 | RefPtr<RegisterID> temp = generator.newTemporary(); | |
3306 | generator.emitGetById(temp.get(), rhs, target.propertyName); | |
ed1e77d3 A |
3307 | if (target.defaultValue) |
3308 | assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue); | |
81345200 A |
3309 | target.pattern->bindValue(generator, temp.get()); |
3310 | } | |
3311 | } | |
3312 | ||
3313 | void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
3314 | { | |
3315 | for (size_t i = 0; i < m_targetPatterns.size(); i++) | |
3316 | m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers); | |
3317 | } | |
3318 | ||
3319 | void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const | |
3320 | { | |
ed1e77d3 A |
3321 | Variable var = generator.variable(m_boundProperty); |
3322 | if (RegisterID* local = var.local()) { | |
3323 | if (var.isReadOnly()) { | |
81345200 A |
3324 | generator.emitReadOnlyExceptionIfNeeded(); |
3325 | return; | |
3326 | } | |
ed1e77d3 A |
3327 | generator.emitMove(local, value); |
3328 | if (generator.vm()->typeProfiler()) | |
3329 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
81345200 A |
3330 | return; |
3331 | } | |
3332 | if (generator.isStrictMode()) | |
3333 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); | |
ed1e77d3 | 3334 | RegisterID* scope = generator.emitResolveScope(nullptr, var); |
81345200 | 3335 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
ed1e77d3 A |
3336 | generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); |
3337 | if (generator.vm()->typeProfiler()) { | |
3338 | generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_boundProperty); | |
3339 | generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); | |
3340 | } | |
81345200 A |
3341 | return; |
3342 | } | |
3343 | ||
3344 | void BindingNode::toString(StringBuilder& builder) const | |
3345 | { | |
3346 | builder.append(m_boundProperty.string()); | |
3347 | } | |
3348 | ||
3349 | void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const | |
3350 | { | |
3351 | identifiers.append(m_boundProperty); | |
3352 | } | |
3353 | ||
3354 | RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*) | |
3355 | { | |
3356 | RELEASE_ASSERT_NOT_REACHED(); | |
3357 | return 0; | |
3358 | } | |
f9bf01c6 A |
3359 | |
3360 | } // namespace JSC |