1 | /* |
2 | * Copyright (C) 1999-2002 Harri Porten ([email protected]) |
3 | * Copyright (C) 2001 Peter Kelly ([email protected]) |
4 | * Copyright (C) 2003-2019 Apple Inc. All rights reserved. |
5 | * Copyright (C) 2007 Cameron Zwarich ([email protected]) |
6 | * Copyright (C) 2007 Maks Orlovich |
7 | * Copyright (C) 2007 Eric Seidel <[email protected]> |
8 | * Copyright (C) 2012 Igalia, S.L. |
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 | |
31 | #include "BuiltinNames.h" |
32 | #include "BytecodeGenerator.h" |
33 | #include "CallFrame.h" |
34 | #include "JIT.h" |
35 | #include "JSCInlines.h" |
36 | #include "JSFunction.h" |
37 | #include "JSGeneratorFunction.h" |
38 | #include "JSGlobalObject.h" |
39 | #include "JSImmutableButterfly.h" |
40 | #include "LabelScope.h" |
41 | #include "Lexer.h" |
42 | #include "Parser.h" |
43 | #include "StackAlignment.h" |
44 | #include "UnlinkedMetadataTableInlines.h" |
45 | #include "YarrFlags.h" |
46 | #include <wtf/Assertions.h> |
47 | #include <wtf/Threading.h> |
48 | #include <wtf/text/StringBuilder.h> |
49 | |
50 | namespace JSC { |
51 | |
52 | /* |
53 | Details of the emitBytecode function. |
54 | |
55 | Return value: The register holding the production's value. |
56 | dst: An optional parameter specifying the most efficient destination at |
57 | which to store the production's value. The callee must honor dst. |
58 | |
59 | The dst argument provides for a crude form of copy propagation. For example, |
60 | |
61 | x = 1 |
62 | |
63 | becomes |
64 | |
65 | load r[x], 1 |
66 | |
67 | instead of |
68 | |
69 | load r0, 1 |
70 | mov r[x], r0 |
71 | |
72 | because the assignment node, "x =", passes r[x] as dst to the number node, "1". |
73 | */ |
74 | |
75 | void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
76 | { |
77 | RegisterID* result = generator.emitNode(this); |
78 | if (fallThroughMode == FallThroughMeansTrue) |
79 | generator.emitJumpIfFalse(result, falseTarget); |
80 | else |
81 | generator.emitJumpIfTrue(result, trueTarget); |
82 | } |
83 | |
84 | // ------------------------------ ThrowableExpressionData -------------------------------- |
85 | |
86 | RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) |
87 | { |
88 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
89 | generator.emitThrowReferenceError(message); |
90 | return generator.newTemporary(); |
91 | } |
92 | |
93 | // ------------------------------ ConstantNode ---------------------------------- |
94 | |
95 | void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
96 | { |
97 | TriState value = jsValue(generator).pureToBoolean(); |
98 | |
99 | if (UNLIKELY(needsDebugHook())) { |
100 | if (value != MixedTriState) |
101 | generator.emitDebugHook(this); |
102 | } |
103 | |
104 | if (value == MixedTriState) |
105 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); |
106 | else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) |
107 | generator.emitJump(trueTarget); |
108 | else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue) |
109 | generator.emitJump(falseTarget); |
110 | |
111 | // All other cases are unconditional fall-throughs, like "if (true)". |
112 | } |
113 | |
114 | RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
115 | { |
116 | if (dst == generator.ignoredResult()) |
117 | return 0; |
118 | return generator.emitLoad(dst, jsValue(generator)); |
119 | } |
120 | |
121 | JSValue StringNode::jsValue(BytecodeGenerator& generator) const |
122 | { |
123 | return generator.addStringConstant(m_value); |
124 | } |
125 | |
126 | JSValue BigIntNode::jsValue(BytecodeGenerator& generator) const |
127 | { |
128 | return generator.addBigIntConstant(m_value, m_radix, m_sign); |
129 | } |
130 | |
131 | // ------------------------------ NumberNode ---------------------------------- |
132 | |
133 | RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
134 | { |
135 | if (dst == generator.ignoredResult()) |
136 | return nullptr; |
137 | return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double); |
138 | } |
139 | |
140 | // ------------------------------ RegExpNode ----------------------------------- |
141 | |
142 | RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
143 | { |
144 | if (dst == generator.ignoredResult()) |
145 | return nullptr; |
146 | |
147 | auto flags = Yarr::parseFlags(m_flags.string()); |
148 | ASSERT(flags.hasValue()); |
149 | RegExp* regExp = RegExp::create(*generator.vm(), m_pattern.string(), flags.value()); |
150 | if (regExp->isValid()) |
151 | return generator.emitNewRegExp(generator.finalDestination(dst), regExp); |
152 | |
153 | const char* messageCharacters = regExp->errorMessage(); |
154 | const Identifier& message = generator.parserArena().identifierArena().makeIdentifier(generator.vm(), bitwise_cast<const LChar*>(messageCharacters), strlen(messageCharacters)); |
155 | generator.emitThrowStaticError(ErrorType::SyntaxError, message); |
156 | return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); |
157 | } |
158 | |
159 | // ------------------------------ ThisNode ------------------------------------- |
160 | |
161 | RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
162 | { |
163 | generator.ensureThis(); |
164 | if (dst == generator.ignoredResult()) |
165 | return 0; |
166 | |
167 | RegisterID* result = generator.move(dst, generator.thisRegister()); |
168 | static const unsigned thisLength = 4; |
169 | generator.emitProfileType(generator.thisRegister(), position(), JSTextPosition(-1, position().offset + thisLength, -1)); |
170 | return result; |
171 | } |
172 | |
173 | // ------------------------------ SuperNode ------------------------------------- |
174 | |
175 | static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator) |
176 | { |
177 | if (generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) { |
178 | RegisterID* derivedConstructor = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(); |
179 | return generator.emitGetById(generator.newTemporary(), derivedConstructor, generator.propertyNames().builtinNames().homeObjectPrivateName()); |
180 | } |
181 | |
182 | RegisterID callee; |
183 | callee.setIndex(CallFrameSlot::callee); |
184 | return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().builtinNames().homeObjectPrivateName()); |
185 | } |
186 | |
187 | static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator) |
188 | { |
189 | RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator); |
190 | return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); |
191 | } |
192 | |
193 | static RegisterID* emitGetSuperFunctionForConstruct(BytecodeGenerator& generator) |
194 | { |
195 | if (generator.isDerivedConstructorContext()) |
196 | return generator.emitGetById(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto); |
197 | |
198 | RegisterID callee; |
199 | callee.setIndex(CallFrameSlot::callee); |
200 | return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().underscoreProto); |
201 | } |
202 | |
203 | RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
204 | { |
205 | RegisterID* result = emitSuperBaseForCallee(generator); |
206 | return generator.move(generator.finalDestination(dst), result); |
207 | } |
208 | |
209 | // ------------------------------ ImportNode ------------------------------------- |
210 | |
211 | RegisterID* ImportNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
212 | { |
213 | RefPtr<RegisterID> importModule = generator.emitGetGlobalPrivate(generator.newTemporary(), generator.propertyNames().builtinNames().importModulePrivateName()); |
214 | CallArguments arguments(generator, nullptr, 1); |
215 | generator.emitLoad(arguments.thisRegister(), jsUndefined()); |
216 | generator.emitNode(arguments.argumentRegister(0), m_expr); |
217 | return generator.emitCall(generator.finalDestination(dst, importModule.get()), importModule.get(), NoExpectedFunction, arguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
218 | } |
219 | |
220 | // ------------------------------ NewTargetNode ---------------------------------- |
221 | |
222 | RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
223 | { |
224 | if (dst == generator.ignoredResult()) |
225 | return nullptr; |
226 | |
227 | return generator.move(dst, generator.newTarget()); |
228 | } |
229 | |
230 | // ------------------------------ ImportMetaNode --------------------------------- |
231 | |
232 | RegisterID* ImportMetaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
233 | { |
234 | return generator.emitNode(dst, m_expr); |
235 | } |
236 | |
237 | // ------------------------------ ResolveNode ---------------------------------- |
238 | |
239 | bool ResolveNode::isPure(BytecodeGenerator& generator) const |
240 | { |
241 | return generator.variable(m_ident).offset().isStack(); |
242 | } |
243 | |
244 | RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
245 | { |
246 | Variable var = generator.variable(m_ident); |
247 | if (RegisterID* local = var.local()) { |
248 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
249 | if (dst == generator.ignoredResult()) |
250 | return nullptr; |
251 | |
252 | generator.emitProfileType(local, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); |
253 | return generator.move(dst, local); |
254 | } |
255 | |
256 | JSTextPosition divot = m_start + m_ident.length(); |
257 | generator.emitExpressionInfo(divot, m_start, divot); |
258 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
259 | RegisterID* finalDest = generator.finalDestination(dst); |
260 | RefPtr<RegisterID> uncheckedResult = generator.newTemporary(); |
261 | generator.emitGetFromScope(uncheckedResult.get(), scope.get(), var, ThrowIfNotFound); |
262 | generator.emitTDZCheckIfNecessary(var, uncheckedResult.get(), nullptr); |
263 | generator.move(finalDest, uncheckedResult.get()); |
264 | generator.emitProfileType(finalDest, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); |
265 | return finalDest; |
266 | } |
267 | |
268 | // ------------------------------ TemplateStringNode ----------------------------------- |
269 | |
270 | RegisterID* TemplateStringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
271 | { |
272 | if (dst == generator.ignoredResult()) |
273 | return nullptr; |
274 | ASSERT(cooked()); |
275 | return generator.emitLoad(dst, JSValue(generator.addStringConstant(*cooked()))); |
276 | } |
277 | |
278 | // ------------------------------ TemplateLiteralNode ----------------------------------- |
279 | |
280 | RegisterID* TemplateLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
281 | { |
282 | if (!m_templateExpressions) { |
283 | TemplateStringNode* templateString = m_templateStrings->value(); |
284 | ASSERT_WITH_MESSAGE(!m_templateStrings->next(), "Only one template element exists because there's no expression in a given template literal." ); |
285 | return generator.emitNode(dst, templateString); |
286 | } |
287 | |
288 | Vector<RefPtr<RegisterID>, 16> temporaryRegisters; |
289 | |
290 | TemplateStringListNode* templateString = m_templateStrings; |
291 | TemplateExpressionListNode* templateExpression = m_templateExpressions; |
292 | for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) { |
293 | // Evaluate TemplateString. |
294 | ASSERT(templateString->value()->cooked()); |
295 | if (!templateString->value()->cooked()->isEmpty()) { |
296 | temporaryRegisters.append(generator.newTemporary()); |
297 | generator.emitNode(temporaryRegisters.last().get(), templateString->value()); |
298 | } |
299 | |
300 | // Evaluate Expression. |
301 | temporaryRegisters.append(generator.newTemporary()); |
302 | generator.emitNode(temporaryRegisters.last().get(), templateExpression->value()); |
303 | generator.emitToString(temporaryRegisters.last().get(), temporaryRegisters.last().get()); |
304 | } |
305 | |
306 | // Evaluate tail TemplateString. |
307 | ASSERT(templateString->value()->cooked()); |
308 | if (!templateString->value()->cooked()->isEmpty()) { |
309 | temporaryRegisters.append(generator.newTemporary()); |
310 | generator.emitNode(temporaryRegisters.last().get(), templateString->value()); |
311 | } |
312 | |
313 | if (temporaryRegisters.size() == 1) |
314 | return generator.emitToString(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get()); |
315 | |
316 | return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); |
317 | } |
318 | |
319 | // ------------------------------ TaggedTemplateNode ----------------------------------- |
320 | |
321 | RegisterID* TaggedTemplateNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
322 | { |
323 | ExpectedFunction expectedFunction = NoExpectedFunction; |
324 | RefPtr<RegisterID> tag = nullptr; |
325 | RefPtr<RegisterID> base = nullptr; |
326 | if (!m_tag->isLocation()) { |
327 | tag = generator.newTemporary(); |
328 | tag = generator.emitNode(tag.get(), m_tag); |
329 | } else if (m_tag->isResolveNode()) { |
330 | ResolveNode* resolve = static_cast<ResolveNode*>(m_tag); |
331 | const Identifier& identifier = resolve->identifier(); |
332 | expectedFunction = generator.expectedFunctionForIdentifier(identifier); |
333 | |
334 | Variable var = generator.variable(identifier); |
335 | if (RegisterID* local = var.local()) { |
336 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
337 | tag = generator.move(generator.newTemporary(), local); |
338 | } else { |
339 | tag = generator.newTemporary(); |
340 | base = generator.newTemporary(); |
341 | |
342 | JSTextPosition newDivot = divotStart() + identifier.length(); |
343 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); |
344 | generator.move(base.get(), generator.emitResolveScope(base.get(), var)); |
345 | generator.emitGetFromScope(tag.get(), base.get(), var, ThrowIfNotFound); |
346 | generator.emitTDZCheckIfNecessary(var, tag.get(), nullptr); |
347 | } |
348 | } else if (m_tag->isBracketAccessorNode()) { |
349 | BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(m_tag); |
350 | base = generator.newTemporary(); |
351 | base = generator.emitNode(base.get(), bracket->base()); |
352 | RefPtr<RegisterID> property = generator.emitNodeForProperty(bracket->subscript()); |
353 | if (bracket->base()->isSuperNode()) { |
354 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
355 | tag = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get()); |
356 | } else |
357 | tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); |
358 | } else { |
359 | ASSERT(m_tag->isDotAccessorNode()); |
360 | DotAccessorNode* dot = static_cast<DotAccessorNode*>(m_tag); |
361 | base = generator.newTemporary(); |
362 | base = generator.emitNode(base.get(), dot->base()); |
363 | if (dot->base()->isSuperNode()) { |
364 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
365 | tag = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), dot->identifier()); |
366 | } else |
367 | tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier()); |
368 | } |
369 | |
370 | RefPtr<RegisterID> templateObject = generator.emitGetTemplateObject(nullptr, this); |
371 | |
372 | unsigned expressionsCount = 0; |
373 | for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) |
374 | ++expressionsCount; |
375 | |
376 | CallArguments callArguments(generator, nullptr, 1 + expressionsCount); |
377 | if (base) |
378 | generator.move(callArguments.thisRegister(), base.get()); |
379 | else |
380 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
381 | |
382 | unsigned argumentIndex = 0; |
383 | generator.move(callArguments.argumentRegister(argumentIndex++), templateObject.get()); |
384 | for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) |
385 | generator.emitNode(callArguments.argumentRegister(argumentIndex++), templateExpression->value()); |
386 | |
387 | return generator.emitCallInTailPosition(generator.finalDestination(dst, tag.get()), tag.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
388 | } |
389 | |
390 | // ------------------------------ ArrayNode ------------------------------------ |
391 | |
392 | RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
393 | { |
394 | bool hadVariableExpression = false; |
395 | unsigned length = 0; |
396 | |
397 | IndexingType recommendedIndexingType = ArrayWithUndecided; |
398 | ElementNode* firstPutElement; |
399 | for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { |
400 | if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) |
401 | break; |
402 | if (!firstPutElement->value()->isConstant()) |
403 | hadVariableExpression = true; |
404 | else |
405 | recommendedIndexingType = leastUpperBoundOfIndexingTypeAndValue(recommendedIndexingType, static_cast<ConstantNode*>(firstPutElement->value())->jsValue(generator)); |
406 | |
407 | ++length; |
408 | } |
409 | |
410 | auto newArray = [&] (RegisterID* dst, ElementNode* elements, unsigned length, bool hadVariableExpression) { |
411 | if (length && !hadVariableExpression) { |
412 | recommendedIndexingType |= CopyOnWrite; |
413 | ASSERT(generator.vm()->heap.isDeferred()); // We run bytecode generator under a DeferGC. If we stopped doing that, we'd need to put a DeferGC here as we filled in these slots. |
414 | auto* array = JSImmutableButterfly::create(*generator.vm(), recommendedIndexingType, length); |
415 | unsigned index = 0; |
416 | for (ElementNode* element = elements; index < length; element = element->next()) { |
417 | ASSERT(element->value()->isConstant()); |
418 | array->setIndex(*generator.vm(), index++, static_cast<ConstantNode*>(element->value())->jsValue(generator)); |
419 | } |
420 | return generator.emitNewArrayBuffer(dst, array, recommendedIndexingType); |
421 | } |
422 | return generator.emitNewArray(dst, elements, length, recommendedIndexingType); |
423 | }; |
424 | |
425 | if (!firstPutElement && !m_elision) |
426 | return newArray(generator.finalDestination(dst), m_element, length, hadVariableExpression); |
427 | |
428 | if (firstPutElement && firstPutElement->value()->isSpreadExpression()) { |
429 | bool hasElision = m_elision; |
430 | if (!hasElision) { |
431 | for (ElementNode* node = firstPutElement; node; node = node->next()) { |
432 | if (node->elision()) { |
433 | hasElision = true; |
434 | break; |
435 | } |
436 | } |
437 | } |
438 | |
439 | if (!hasElision) |
440 | return generator.emitNewArrayWithSpread(generator.finalDestination(dst), m_element); |
441 | } |
442 | |
443 | RefPtr<RegisterID> array = newArray(generator.tempDestination(dst), m_element, length, hadVariableExpression); |
444 | ElementNode* n = firstPutElement; |
445 | for (; n; n = n->next()) { |
446 | if (n->value()->isSpreadExpression()) |
447 | goto handleSpread; |
448 | RefPtr<RegisterID> value = generator.emitNode(n->value()); |
449 | length += n->elision(); |
450 | |
451 | RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(length++)); |
452 | generator.emitDirectPutByVal(array.get(), index.get(), value.get()); |
453 | } |
454 | |
455 | if (m_elision) { |
456 | RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); |
457 | generator.emitPutById(array.get(), generator.propertyNames().length, value); |
458 | } |
459 | |
460 | return generator.move(dst, array.get()); |
461 | |
462 | handleSpread: |
463 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(length)); |
464 | auto spreader = scopedLambda<void(BytecodeGenerator&, RegisterID*)>([array, index](BytecodeGenerator& generator, RegisterID* value) |
465 | { |
466 | generator.emitDirectPutByVal(array.get(), index.get(), value); |
467 | generator.emitInc(index.get()); |
468 | }); |
469 | for (; n; n = n->next()) { |
470 | if (n->elision()) |
471 | generator.emitBinaryOp<OpAdd>(index.get(), index.get(), generator.emitLoad(0, jsNumber(n->elision())), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); |
472 | if (n->value()->isSpreadExpression()) { |
473 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(n->value()); |
474 | generator.emitEnumeration(spread, spread->expression(), spreader); |
475 | } else { |
476 | generator.emitDirectPutByVal(array.get(), index.get(), generator.emitNode(n->value())); |
477 | generator.emitInc(index.get()); |
478 | } |
479 | } |
480 | |
481 | if (m_elision) { |
482 | generator.emitBinaryOp<OpAdd>(index.get(), index.get(), generator.emitLoad(0, jsNumber(m_elision)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); |
483 | generator.emitPutById(array.get(), generator.propertyNames().length, index.get()); |
484 | } |
485 | return generator.move(dst, array.get()); |
486 | } |
487 | |
488 | bool ArrayNode::isSimpleArray() const |
489 | { |
490 | if (m_elision || m_optional) |
491 | return false; |
492 | for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { |
493 | if (ptr->elision()) |
494 | return false; |
495 | if (ptr->value()->isSpreadExpression()) |
496 | return false; |
497 | } |
498 | return true; |
499 | } |
500 | |
501 | ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, int lineNumber, int startPosition) const |
502 | { |
503 | ASSERT(!m_elision && !m_optional); |
504 | ElementNode* ptr = m_element; |
505 | if (!ptr) |
506 | return 0; |
507 | JSTokenLocation location; |
508 | location.line = lineNumber; |
509 | location.startOffset = startPosition; |
510 | ArgumentListNode* head = new (parserArena) ArgumentListNode(location, ptr->value()); |
511 | ArgumentListNode* tail = head; |
512 | ptr = ptr->next(); |
513 | for (; ptr; ptr = ptr->next()) { |
514 | ASSERT(!ptr->elision()); |
515 | tail = new (parserArena) ArgumentListNode(location, tail, ptr->value()); |
516 | } |
517 | return head; |
518 | } |
519 | |
520 | // ------------------------------ ObjectLiteralNode ---------------------------- |
521 | |
522 | RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
523 | { |
524 | if (!m_list) { |
525 | if (dst == generator.ignoredResult()) |
526 | return 0; |
527 | return generator.emitNewObject(generator.finalDestination(dst)); |
528 | } |
529 | RefPtr<RegisterID> newObj = generator.emitNewObject(generator.tempDestination(dst)); |
530 | generator.emitNode(newObj.get(), m_list); |
531 | return generator.move(dst, newObj.get()); |
532 | } |
533 | |
534 | // ------------------------------ PropertyListNode ----------------------------- |
535 | |
536 | static inline void emitPutHomeObject(BytecodeGenerator& generator, RegisterID* function, RegisterID* homeObject) |
537 | { |
538 | generator.emitPutById(function, generator.propertyNames().builtinNames().homeObjectPrivateName(), homeObject); |
539 | } |
540 | |
541 | RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype) |
542 | { |
543 | // Fast case: this loop just handles regular value properties. |
544 | PropertyListNode* p = this; |
545 | RegisterID* dst = nullptr; |
546 | for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) { |
547 | dst = p->m_node->isInstanceClassProperty() ? prototype : dstOrConstructor; |
548 | emitPutConstantProperty(generator, dst, *p->m_node); |
549 | } |
550 | |
551 | // Were there any get/set properties? |
552 | if (p) { |
553 | // Build a list of getter/setter pairs to try to put them at the same time. If we encounter |
554 | // a computed property or a spread, just emit everything as that may override previous values. |
555 | bool canOverrideProperties = false; |
556 | |
557 | typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair; |
558 | typedef HashMap<UniquedStringImpl*, GetterSetterPair, IdentifierRepHash> GetterSetterMap; |
559 | GetterSetterMap instanceMap; |
560 | GetterSetterMap staticMap; |
561 | |
562 | // Build a map, pairing get/set values together. |
563 | for (PropertyListNode* q = p; q; q = q->m_next) { |
564 | PropertyNode* node = q->m_node; |
565 | if (node->m_type & PropertyNode::Computed || node->m_type & PropertyNode::Spread) { |
566 | canOverrideProperties = true; |
567 | break; |
568 | } |
569 | |
570 | if (node->m_type & PropertyNode::Constant) |
571 | continue; |
572 | |
573 | // Duplicates are possible. |
574 | GetterSetterPair pair(node, static_cast<PropertyNode*>(nullptr)); |
575 | GetterSetterMap& map = node->isStaticClassProperty() ? staticMap : instanceMap; |
576 | GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); |
577 | auto& resultPair = result.iterator->value; |
578 | if (!result.isNewEntry) { |
579 | if (resultPair.first->m_type == node->m_type) { |
580 | resultPair.first->setIsOverriddenByDuplicate(); |
581 | resultPair.first = node; |
582 | } else { |
583 | if (resultPair.second) |
584 | resultPair.second->setIsOverriddenByDuplicate(); |
585 | resultPair.second = node; |
586 | } |
587 | } |
588 | } |
589 | |
590 | // Iterate over the remaining properties in the list. |
591 | for (; p; p = p->m_next) { |
592 | PropertyNode* node = p->m_node; |
593 | dst = node->isInstanceClassProperty() ? prototype : dstOrConstructor; |
594 | |
595 | // Handle regular values. |
596 | if (node->m_type & PropertyNode::Constant) { |
597 | emitPutConstantProperty(generator, dst, *node); |
598 | continue; |
599 | } else if (node->m_type & PropertyNode::Spread) { |
600 | generator.emitNode(dst, node->m_assign); |
601 | continue; |
602 | } |
603 | |
604 | RefPtr<RegisterID> value = generator.emitNode(node->m_assign); |
605 | bool needsSuperBinding = node->needsSuperBinding(); |
606 | if (needsSuperBinding) |
607 | emitPutHomeObject(generator, value.get(), dst); |
608 | |
609 | unsigned attributes = node->isClassProperty() ? (PropertyAttribute::Accessor | PropertyAttribute::DontEnum) : static_cast<unsigned>(PropertyAttribute::Accessor); |
610 | |
611 | ASSERT(node->m_type & (PropertyNode::Getter | PropertyNode::Setter)); |
612 | |
613 | // This is a get/set property which may be overridden by a computed property or spread later. |
614 | if (canOverrideProperties) { |
615 | // Computed accessors. |
616 | if (node->m_type & PropertyNode::Computed) { |
617 | RefPtr<RegisterID> propertyName = generator.emitNode(node->m_expression); |
618 | generator.emitSetFunctionNameIfNeeded(node->m_assign, value.get(), propertyName.get()); |
619 | if (node->m_type & PropertyNode::Getter) |
620 | generator.emitPutGetterByVal(dst, propertyName.get(), attributes, value.get()); |
621 | else |
622 | generator.emitPutSetterByVal(dst, propertyName.get(), attributes, value.get()); |
623 | continue; |
624 | } |
625 | |
626 | if (node->m_type & PropertyNode::Getter) |
627 | generator.emitPutGetterById(dst, *node->name(), attributes, value.get()); |
628 | else |
629 | generator.emitPutSetterById(dst, *node->name(), attributes, value.get()); |
630 | continue; |
631 | } |
632 | |
633 | // This is a get/set property pair. |
634 | GetterSetterMap& map = node->isStaticClassProperty() ? staticMap : instanceMap; |
635 | GetterSetterMap::iterator it = map.find(node->name()->impl()); |
636 | ASSERT(it != map.end()); |
637 | GetterSetterPair& pair = it->value; |
638 | |
639 | // Was this already generated as a part of its partner? |
640 | if (pair.second == node || node->isOverriddenByDuplicate()) |
641 | continue; |
642 | |
643 | // Generate the paired node now. |
644 | RefPtr<RegisterID> getterReg; |
645 | RefPtr<RegisterID> setterReg; |
646 | RegisterID* secondReg = nullptr; |
647 | |
648 | if (node->m_type & PropertyNode::Getter) { |
649 | getterReg = value; |
650 | if (pair.second) { |
651 | ASSERT(pair.second->m_type & PropertyNode::Setter); |
652 | setterReg = generator.emitNode(pair.second->m_assign); |
653 | secondReg = setterReg.get(); |
654 | } else { |
655 | setterReg = generator.newTemporary(); |
656 | generator.emitLoad(setterReg.get(), jsUndefined()); |
657 | } |
658 | } else { |
659 | ASSERT(node->m_type & PropertyNode::Setter); |
660 | setterReg = value; |
661 | if (pair.second) { |
662 | ASSERT(pair.second->m_type & PropertyNode::Getter); |
663 | getterReg = generator.emitNode(pair.second->m_assign); |
664 | secondReg = getterReg.get(); |
665 | } else { |
666 | getterReg = generator.newTemporary(); |
667 | generator.emitLoad(getterReg.get(), jsUndefined()); |
668 | } |
669 | } |
670 | |
671 | ASSERT(!pair.second || needsSuperBinding == pair.second->needsSuperBinding()); |
672 | if (needsSuperBinding && pair.second) |
673 | emitPutHomeObject(generator, secondReg, dst); |
674 | |
675 | generator.emitPutGetterSetter(dst, *node->name(), attributes, getterReg.get(), setterReg.get()); |
676 | } |
677 | } |
678 | |
679 | return dstOrConstructor; |
680 | } |
681 | |
682 | void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node) |
683 | { |
684 | RefPtr<RegisterID> value = generator.emitNode(node.m_assign); |
685 | if (node.needsSuperBinding()) |
686 | emitPutHomeObject(generator, value.get(), newObj); |
687 | |
688 | if (node.isClassProperty()) { |
689 | ASSERT(node.needsSuperBinding()); |
690 | RefPtr<RegisterID> propertyNameRegister; |
691 | if (node.name()) |
692 | propertyNameRegister = generator.emitLoad(nullptr, *node.name()); |
693 | else |
694 | propertyNameRegister = generator.emitNode(node.m_expression); |
695 | |
696 | generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyNameRegister.get()); |
697 | generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); |
698 | return; |
699 | } |
700 | if (const auto* identifier = node.name()) { |
701 | Optional<uint32_t> optionalIndex = parseIndex(*identifier); |
702 | if (!optionalIndex) { |
703 | generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType()); |
704 | return; |
705 | } |
706 | |
707 | RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(optionalIndex.value())); |
708 | generator.emitDirectPutByVal(newObj, index.get(), value.get()); |
709 | return; |
710 | } |
711 | RefPtr<RegisterID> propertyName = generator.emitNode(node.m_expression); |
712 | generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyName.get()); |
713 | generator.emitDirectPutByVal(newObj, propertyName.get(), value.get()); |
714 | } |
715 | |
716 | // ------------------------------ BracketAccessorNode -------------------------------- |
717 | |
718 | static bool isNonIndexStringElement(ExpressionNode& element) |
719 | { |
720 | return element.isString() && !parseIndex(static_cast<StringNode&>(element).value()); |
721 | } |
722 | |
723 | RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
724 | { |
725 | if (m_base->isSuperNode()) { |
726 | RefPtr<RegisterID> finalDest = generator.finalDestination(dst); |
727 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
728 | RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator); |
729 | |
730 | if (isNonIndexStringElement(*m_subscript)) { |
731 | const Identifier& id = static_cast<StringNode*>(m_subscript)->value(); |
732 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
733 | generator.emitGetById(finalDest.get(), superBase.get(), thisValue.get(), id); |
734 | } else { |
735 | RefPtr<RegisterID> subscript = generator.emitNodeForProperty(m_subscript); |
736 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
737 | generator.emitGetByVal(finalDest.get(), superBase.get(), thisValue.get(), subscript.get()); |
738 | } |
739 | |
740 | generator.emitProfileType(finalDest.get(), divotStart(), divotEnd()); |
741 | return finalDest.get(); |
742 | } |
743 | |
744 | RegisterID* ret; |
745 | RefPtr<RegisterID> finalDest = generator.finalDestination(dst); |
746 | |
747 | if (isNonIndexStringElement(*m_subscript)) { |
748 | RefPtr<RegisterID> base = generator.emitNode(m_base); |
749 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
750 | ret = generator.emitGetById(finalDest.get(), base.get(), static_cast<StringNode*>(m_subscript)->value()); |
751 | } else { |
752 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); |
753 | RegisterID* property = generator.emitNodeForProperty(m_subscript); |
754 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
755 | ret = generator.emitGetByVal(finalDest.get(), base.get(), property); |
756 | } |
757 | |
758 | generator.emitProfileType(finalDest.get(), divotStart(), divotEnd()); |
759 | return ret; |
760 | } |
761 | |
762 | // ------------------------------ DotAccessorNode -------------------------------- |
763 | |
764 | RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
765 | { |
766 | bool baseIsSuper = m_base->isSuperNode(); |
767 | RefPtr<RegisterID> base = baseIsSuper ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); |
768 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
769 | RegisterID* finalDest = generator.finalDestination(dst); |
770 | RegisterID* ret; |
771 | if (baseIsSuper) { |
772 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
773 | ret = generator.emitGetById(finalDest, base.get(), thisValue.get(), m_ident); |
774 | } else |
775 | ret = generator.emitGetById(finalDest, base.get(), m_ident); |
776 | generator.emitProfileType(finalDest, divotStart(), divotEnd()); |
777 | return ret; |
778 | } |
779 | |
780 | // ------------------------------ ArgumentListNode ----------------------------- |
781 | |
782 | RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
783 | { |
784 | ASSERT(m_expr); |
785 | return generator.emitNode(dst, m_expr); |
786 | } |
787 | |
788 | // ------------------------------ NewExprNode ---------------------------------- |
789 | |
790 | RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
791 | { |
792 | ExpectedFunction expectedFunction; |
793 | if (m_expr->isResolveNode()) |
794 | expectedFunction = generator.expectedFunctionForIdentifier(static_cast<ResolveNode*>(m_expr)->identifier()); |
795 | else |
796 | expectedFunction = NoExpectedFunction; |
797 | RefPtr<RegisterID> func = generator.emitNode(m_expr); |
798 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
799 | CallArguments callArguments(generator, m_args); |
800 | return generator.emitConstruct(returnValue.get(), func.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
801 | } |
802 | |
803 | CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments) |
804 | : m_argumentsNode(argumentsNode) |
805 | , m_padding(0) |
806 | { |
807 | size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register. |
808 | if (argumentsNode) { |
809 | for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next) |
810 | ++argumentCountIncludingThis; |
811 | } |
812 | |
813 | m_argv.grow(argumentCountIncludingThis); |
814 | for (int i = argumentCountIncludingThis - 1; i >= 0; --i) { |
815 | m_argv[i] = generator.newTemporary(); |
816 | ASSERT(static_cast<size_t>(i) == m_argv.size() - 1 || m_argv[i]->index() == m_argv[i + 1]->index() - 1); |
817 | } |
818 | |
819 | // We need to ensure that the frame size is stack-aligned |
820 | while ((CallFrame::headerSizeInRegisters + m_argv.size()) % stackAlignmentRegisters()) { |
821 | m_argv.insert(0, generator.newTemporary()); |
822 | m_padding++; |
823 | } |
824 | |
825 | while (stackOffset() % stackAlignmentRegisters()) { |
826 | m_argv.insert(0, generator.newTemporary()); |
827 | m_padding++; |
828 | } |
829 | } |
830 | |
831 | // ------------------------------ EvalFunctionCallNode ---------------------------------- |
832 | |
833 | RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
834 | { |
835 | // We need try to load 'this' before call eval in constructor, because 'this' can created by 'super' in some of the arrow function |
836 | // var A = class A { |
837 | // constructor () { this.id = 'A'; } |
838 | // } |
839 | // |
840 | // var B = class B extend A { |
841 | // constructor () { |
842 | // var arrow = () => super(); |
843 | // arrow(); |
844 | // eval("this.id = 'B'"); |
845 | // } |
846 | // } |
847 | if (generator.constructorKind() == ConstructorKind::Extends && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction()) |
848 | generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); |
849 | |
850 | Variable var = generator.variable(generator.propertyNames().eval); |
851 | if (RegisterID* local = var.local()) { |
852 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
853 | RefPtr<RegisterID> func = generator.move(generator.tempDestination(dst), local); |
854 | CallArguments callArguments(generator, m_args); |
855 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
856 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
857 | } |
858 | |
859 | RefPtr<RegisterID> func = generator.newTemporary(); |
860 | CallArguments callArguments(generator, m_args); |
861 | JSTextPosition newDivot = divotStart() + 4; |
862 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); |
863 | generator.move( |
864 | callArguments.thisRegister(), |
865 | generator.emitResolveScope(callArguments.thisRegister(), var)); |
866 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); |
867 | generator.emitTDZCheckIfNecessary(var, func.get(), nullptr); |
868 | return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
869 | } |
870 | |
871 | // ------------------------------ FunctionCallValueNode ---------------------------------- |
872 | |
873 | RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
874 | { |
875 | if (m_expr->isSuperNode()) { |
876 | RefPtr<RegisterID> func = emitGetSuperFunctionForConstruct(generator); |
877 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
878 | CallArguments callArguments(generator, m_args); |
879 | |
880 | ASSERT(generator.isConstructor() || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext); |
881 | ASSERT(generator.constructorKind() == ConstructorKind::Extends || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext); |
882 | RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), generator.newTarget(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); |
883 | |
884 | bool isConstructorKindDerived = generator.constructorKind() == ConstructorKind::Extends; |
885 | bool doWeUseArrowFunctionInConstructor = isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext(); |
886 | |
887 | if (generator.isDerivedConstructorContext() || (doWeUseArrowFunctionInConstructor && generator.isSuperCallUsedInInnerArrowFunction())) |
888 | generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); |
889 | |
890 | Ref<Label> thisIsEmptyLabel = generator.newLabel(); |
891 | generator.emitJumpIfTrue(generator.emitIsEmpty(generator.newTemporary(), generator.thisRegister()), thisIsEmptyLabel.get()); |
892 | generator.emitThrowReferenceError("'super()' can't be called more than once in a constructor."_s ); |
893 | generator.emitLabel(thisIsEmptyLabel.get()); |
894 | |
895 | generator.move(generator.thisRegister(), ret); |
896 | |
897 | if (generator.isDerivedConstructorContext() || doWeUseArrowFunctionInConstructor) |
898 | generator.emitPutThisToArrowFunctionContextScope(); |
899 | |
900 | return ret; |
901 | } |
902 | RefPtr<RegisterID> func = generator.emitNode(m_expr); |
903 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
904 | CallArguments callArguments(generator, m_args); |
905 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
906 | RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
907 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
908 | return ret; |
909 | } |
910 | |
911 | // ------------------------------ FunctionCallResolveNode ---------------------------------- |
912 | |
913 | RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
914 | { |
915 | if (UNLIKELY(m_ident == generator.vm()->propertyNames->builtinNames().assertPrivateName())) { |
916 | if (ASSERT_DISABLED) |
917 | return generator.move(dst, generator.emitLoad(nullptr, jsUndefined())); |
918 | } |
919 | |
920 | ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); |
921 | |
922 | Variable var = generator.variable(m_ident); |
923 | if (RegisterID* local = var.local()) { |
924 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
925 | RefPtr<RegisterID> func = generator.move(generator.tempDestination(dst), local); |
926 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
927 | CallArguments callArguments(generator, m_args); |
928 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
929 | // This passes NoExpectedFunction because we expect that if the function is in a |
930 | // local variable, then it's not one of our built-in constructors. |
931 | RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
932 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
933 | return ret; |
934 | } |
935 | |
936 | RefPtr<RegisterID> func = generator.newTemporary(); |
937 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); |
938 | CallArguments callArguments(generator, m_args); |
939 | |
940 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
941 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); |
942 | generator.move( |
943 | callArguments.thisRegister(), |
944 | generator.emitResolveScope(callArguments.thisRegister(), var)); |
945 | generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); |
946 | generator.emitTDZCheckIfNecessary(var, func.get(), nullptr); |
947 | RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
948 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
949 | return ret; |
950 | } |
951 | |
952 | // ------------------------------ BytecodeIntrinsicNode ---------------------------------- |
953 | |
954 | RegisterID* BytecodeIntrinsicNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
955 | { |
956 | return (this->*m_emitter)(generator, dst); |
957 | } |
958 | |
959 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getByIdDirect(BytecodeGenerator& generator, RegisterID* dst) |
960 | { |
961 | ArgumentListNode* node = m_args->m_listNode; |
962 | RefPtr<RegisterID> base = generator.emitNode(node); |
963 | node = node->m_next; |
964 | ASSERT(node->m_expr->isString()); |
965 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
966 | ASSERT(!node->m_next); |
967 | return generator.emitDirectGetById(generator.finalDestination(dst), base.get(), ident); |
968 | } |
969 | |
970 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getByIdDirectPrivate(BytecodeGenerator& generator, RegisterID* dst) |
971 | { |
972 | ArgumentListNode* node = m_args->m_listNode; |
973 | RefPtr<RegisterID> base = generator.emitNode(node); |
974 | node = node->m_next; |
975 | ASSERT(node->m_expr->isString()); |
976 | SymbolImpl* symbol = generator.vm()->propertyNames->lookUpPrivateName(static_cast<StringNode*>(node->m_expr)->value()); |
977 | ASSERT(symbol); |
978 | ASSERT(!node->m_next); |
979 | return generator.emitDirectGetById(generator.finalDestination(dst), base.get(), generator.parserArena().identifierArena().makeIdentifier(generator.vm(), symbol)); |
980 | } |
981 | |
982 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_argument(BytecodeGenerator& generator, RegisterID* dst) |
983 | { |
984 | ArgumentListNode* node = m_args->m_listNode; |
985 | ASSERT(node->m_expr->isNumber()); |
986 | double value = static_cast<NumberNode*>(node->m_expr)->value(); |
987 | int32_t index = static_cast<int32_t>(value); |
988 | ASSERT(value == index); |
989 | ASSERT(index >= 0); |
990 | ASSERT(!node->m_next); |
991 | |
992 | // The body functions of generator and async have different mechanism for arguments. |
993 | ASSERT(generator.parseMode() != SourceParseMode::GeneratorBodyMode); |
994 | ASSERT(!isAsyncFunctionBodyParseMode(generator.parseMode())); |
995 | |
996 | return generator.emitGetArgument(generator.finalDestination(dst), index); |
997 | } |
998 | |
999 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_argumentCount(BytecodeGenerator& generator, RegisterID* dst) |
1000 | { |
1001 | ASSERT(!m_args->m_listNode); |
1002 | |
1003 | return generator.emitArgumentCount(generator.finalDestination(dst)); |
1004 | } |
1005 | |
1006 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByIdDirect(BytecodeGenerator& generator, RegisterID* dst) |
1007 | { |
1008 | ArgumentListNode* node = m_args->m_listNode; |
1009 | RefPtr<RegisterID> base = generator.emitNode(node); |
1010 | node = node->m_next; |
1011 | ASSERT(node->m_expr->isString()); |
1012 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
1013 | node = node->m_next; |
1014 | RefPtr<RegisterID> value = generator.emitNode(node); |
1015 | |
1016 | ASSERT(!node->m_next); |
1017 | |
1018 | return generator.move(dst, generator.emitDirectPutById(base.get(), ident, value.get(), PropertyNode::KnownDirect)); |
1019 | } |
1020 | |
1021 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByIdDirectPrivate(BytecodeGenerator& generator, RegisterID* dst) |
1022 | { |
1023 | ArgumentListNode* node = m_args->m_listNode; |
1024 | RefPtr<RegisterID> base = generator.emitNode(node); |
1025 | node = node->m_next; |
1026 | ASSERT(node->m_expr->isString()); |
1027 | SymbolImpl* symbol = generator.vm()->propertyNames->lookUpPrivateName(static_cast<StringNode*>(node->m_expr)->value()); |
1028 | ASSERT(symbol); |
1029 | node = node->m_next; |
1030 | RefPtr<RegisterID> value = generator.emitNode(node); |
1031 | |
1032 | ASSERT(!node->m_next); |
1033 | |
1034 | return generator.move(dst, generator.emitDirectPutById(base.get(), generator.parserArena().identifierArena().makeIdentifier(generator.vm(), symbol), value.get(), PropertyNode::KnownDirect)); |
1035 | } |
1036 | |
1037 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByValDirect(BytecodeGenerator& generator, RegisterID* dst) |
1038 | { |
1039 | ArgumentListNode* node = m_args->m_listNode; |
1040 | RefPtr<RegisterID> base = generator.emitNode(node); |
1041 | node = node->m_next; |
1042 | RefPtr<RegisterID> index = generator.emitNodeForProperty(node); |
1043 | node = node->m_next; |
1044 | RefPtr<RegisterID> value = generator.emitNode(node); |
1045 | |
1046 | ASSERT(!node->m_next); |
1047 | |
1048 | return generator.move(dst, generator.emitDirectPutByVal(base.get(), index.get(), value.get())); |
1049 | } |
1050 | |
1051 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_tailCallForwardArguments(BytecodeGenerator& generator, RegisterID* dst) |
1052 | { |
1053 | ArgumentListNode* node = m_args->m_listNode; |
1054 | RefPtr<RegisterID> function = generator.emitNode(node); |
1055 | node = node->m_next; |
1056 | RefPtr<RegisterID> thisRegister = generator.emitNode(node); |
1057 | ASSERT(!node->m_next); |
1058 | |
1059 | RefPtr<RegisterID> finalDst = generator.finalDestination(dst); |
1060 | return generator.emitCallForwardArgumentsInTailPosition(finalDst.get(), function.get(), thisRegister.get(), generator.newTemporary(), 0, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
1061 | } |
1062 | |
1063 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_throwTypeError(BytecodeGenerator& generator, RegisterID* dst) |
1064 | { |
1065 | ArgumentListNode* node = m_args->m_listNode; |
1066 | ASSERT(!node->m_next); |
1067 | if (node->m_expr->isString()) { |
1068 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
1069 | generator.emitThrowTypeError(ident); |
1070 | } else { |
1071 | RefPtr<RegisterID> message = generator.emitNode(node); |
1072 | generator.emitThrowStaticError(ErrorType::TypeError, message.get()); |
1073 | } |
1074 | return dst; |
1075 | } |
1076 | |
1077 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_throwRangeError(BytecodeGenerator& generator, RegisterID* dst) |
1078 | { |
1079 | ArgumentListNode* node = m_args->m_listNode; |
1080 | ASSERT(!node->m_next); |
1081 | if (node->m_expr->isString()) { |
1082 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
1083 | generator.emitThrowRangeError(ident); |
1084 | } else { |
1085 | RefPtr<RegisterID> message = generator.emitNode(node); |
1086 | generator.emitThrowStaticError(ErrorType::RangeError, message.get()); |
1087 | } |
1088 | |
1089 | return dst; |
1090 | } |
1091 | |
1092 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_throwOutOfMemoryError(BytecodeGenerator& generator, RegisterID* dst) |
1093 | { |
1094 | ASSERT(!m_args->m_listNode); |
1095 | |
1096 | generator.emitThrowOutOfMemoryError(); |
1097 | return dst; |
1098 | } |
1099 | |
1100 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_tryGetById(BytecodeGenerator& generator, RegisterID* dst) |
1101 | { |
1102 | ArgumentListNode* node = m_args->m_listNode; |
1103 | RefPtr<RegisterID> base = generator.emitNode(node); |
1104 | node = node->m_next; |
1105 | |
1106 | // Since this is a builtin we expect the creator to use a string literal as the second argument. |
1107 | ASSERT(node->m_expr->isString()); |
1108 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
1109 | ASSERT(!node->m_next); |
1110 | |
1111 | RefPtr<RegisterID> finalDest = generator.finalDestination(dst); |
1112 | return generator.emitTryGetById(finalDest.get(), base.get(), ident); |
1113 | } |
1114 | |
1115 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toNumber(BytecodeGenerator& generator, RegisterID* dst) |
1116 | { |
1117 | ArgumentListNode* node = m_args->m_listNode; |
1118 | RefPtr<RegisterID> src = generator.emitNode(node); |
1119 | ASSERT(!node->m_next); |
1120 | |
1121 | return generator.move(dst, generator.emitToNumber(generator.tempDestination(dst), src.get())); |
1122 | } |
1123 | |
1124 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toString(BytecodeGenerator& generator, RegisterID* dst) |
1125 | { |
1126 | ArgumentListNode* node = m_args->m_listNode; |
1127 | RefPtr<RegisterID> src = generator.emitNode(node); |
1128 | ASSERT(!node->m_next); |
1129 | |
1130 | return generator.move(dst, generator.emitToString(generator.tempDestination(dst), src.get())); |
1131 | } |
1132 | |
1133 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toObject(BytecodeGenerator& generator, RegisterID* dst) |
1134 | { |
1135 | ArgumentListNode* node = m_args->m_listNode; |
1136 | RefPtr<RegisterID> src = generator.emitNode(node); |
1137 | node = node->m_next; |
1138 | |
1139 | RefPtr<RegisterID> temp = generator.tempDestination(dst); |
1140 | if (node) { |
1141 | ASSERT(node->m_expr->isString()); |
1142 | const Identifier& message = static_cast<StringNode*>(node->m_expr)->value(); |
1143 | ASSERT(!node->m_next); |
1144 | return generator.move(dst, generator.emitToObject(temp.get(), src.get(), message)); |
1145 | } |
1146 | return generator.move(dst, generator.emitToObject(temp.get(), src.get(), generator.vm()->propertyNames->emptyIdentifier)); |
1147 | } |
1148 | |
1149 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_idWithProfile(BytecodeGenerator& generator, RegisterID* dst) |
1150 | { |
1151 | ArgumentListNode* node = m_args->m_listNode; |
1152 | RefPtr<RegisterID> idValue = generator.newTemporary(); |
1153 | generator.emitNode(idValue.get(), node); |
1154 | SpeculatedType speculation = SpecNone; |
1155 | while (node->m_next) { |
1156 | node = node->m_next; |
1157 | ASSERT(node->m_expr->isString()); |
1158 | const Identifier& ident = static_cast<StringNode*>(node->m_expr)->value(); |
1159 | speculation |= speculationFromString(ident.utf8().data()); |
1160 | } |
1161 | |
1162 | return generator.move(dst, generator.emitIdWithProfile(idValue.get(), speculation)); |
1163 | } |
1164 | |
1165 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isJSArray(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1166 | { |
1167 | ArgumentListNode* node = m_args->m_listNode; |
1168 | RefPtr<RegisterID> src = generator.emitNode(node); |
1169 | ASSERT(!node->m_next); |
1170 | |
1171 | return generator.move(dst, generator.emitIsJSArray(generator.tempDestination(dst), src.get())); |
1172 | } |
1173 | |
1174 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isProxyObject(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1175 | { |
1176 | ArgumentListNode* node = m_args->m_listNode; |
1177 | RefPtr<RegisterID> src = generator.emitNode(node); |
1178 | ASSERT(!node->m_next); |
1179 | |
1180 | return generator.move(dst, generator.emitIsProxyObject(generator.tempDestination(dst), src.get())); |
1181 | } |
1182 | |
1183 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isRegExpObject(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1184 | { |
1185 | ArgumentListNode* node = m_args->m_listNode; |
1186 | RefPtr<RegisterID> src = generator.emitNode(node); |
1187 | ASSERT(!node->m_next); |
1188 | |
1189 | return generator.move(dst, generator.emitIsRegExpObject(generator.tempDestination(dst), src.get())); |
1190 | } |
1191 | |
1192 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isObject(BytecodeGenerator& generator, RegisterID* dst) |
1193 | { |
1194 | ArgumentListNode* node = m_args->m_listNode; |
1195 | RefPtr<RegisterID> src = generator.emitNode(node); |
1196 | ASSERT(!node->m_next); |
1197 | |
1198 | return generator.move(dst, generator.emitIsObject(generator.tempDestination(dst), src.get())); |
1199 | } |
1200 | |
1201 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isDerivedArray(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1202 | { |
1203 | ArgumentListNode* node = m_args->m_listNode; |
1204 | RefPtr<RegisterID> src = generator.emitNode(node); |
1205 | ASSERT(!node->m_next); |
1206 | |
1207 | return generator.move(dst, generator.emitIsDerivedArray(generator.tempDestination(dst), src.get())); |
1208 | } |
1209 | |
1210 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isMap(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1211 | { |
1212 | ArgumentListNode* node = m_args->m_listNode; |
1213 | RefPtr<RegisterID> src = generator.emitNode(node); |
1214 | ASSERT(!node->m_next); |
1215 | |
1216 | return generator.move(dst, generator.emitIsMap(generator.tempDestination(dst), src.get())); |
1217 | } |
1218 | |
1219 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isSet(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1220 | { |
1221 | ArgumentListNode* node = m_args->m_listNode; |
1222 | RefPtr<RegisterID> src = generator.emitNode(node); |
1223 | ASSERT(!node->m_next); |
1224 | |
1225 | return generator.move(dst, generator.emitIsSet(generator.tempDestination(dst), src.get())); |
1226 | } |
1227 | |
1228 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isUndefinedOrNull(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1229 | { |
1230 | ArgumentListNode* node = m_args->m_listNode; |
1231 | RefPtr<RegisterID> src = generator.emitNode(node); |
1232 | ASSERT(!node->m_next); |
1233 | |
1234 | return generator.move(dst, generator.emitIsUndefinedOrNull(generator.tempDestination(dst), src.get())); |
1235 | } |
1236 | |
1237 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_newArrayWithSize(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1238 | { |
1239 | ArgumentListNode* node = m_args->m_listNode; |
1240 | RefPtr<RegisterID> size = generator.emitNode(node); |
1241 | ASSERT(!node->m_next); |
1242 | |
1243 | RefPtr<RegisterID> finalDestination = generator.finalDestination(dst); |
1244 | generator.emitNewArrayWithSize(finalDestination.get(), size.get()); |
1245 | return finalDestination.get(); |
1246 | } |
1247 | |
1248 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_defineEnumerableWritableConfigurableDataProperty(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst) |
1249 | { |
1250 | ArgumentListNode* node = m_args->m_listNode; |
1251 | RefPtr<RegisterID> newObj = generator.emitNode(node); |
1252 | node = node->m_next; |
1253 | RefPtr<RegisterID> propertyNameRegister = generator.emitNode(node); |
1254 | node = node->m_next; |
1255 | RefPtr<RegisterID> value = generator.emitNode(node); |
1256 | ASSERT(!node->m_next); |
1257 | |
1258 | generator.emitCallDefineProperty(newObj.get(), propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position); |
1259 | return dst; |
1260 | } |
1261 | |
1262 | #define JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS(name) \ |
1263 | RegisterID* BytecodeIntrinsicNode::emit_intrinsic_##name(BytecodeGenerator& generator, RegisterID* dst) \ |
1264 | { \ |
1265 | ASSERT(!m_args); \ |
1266 | ASSERT(type() == Type::Constant); \ |
1267 | if (dst == generator.ignoredResult()) \ |
1268 | return nullptr; \ |
1269 | return generator.emitLoad(dst, generator.vm()->bytecodeIntrinsicRegistry().name##Value(generator)); \ |
1270 | } |
1271 | JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS) |
1272 | #undef JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS |
1273 | |
1274 | // ------------------------------ FunctionCallBracketNode ---------------------------------- |
1275 | |
1276 | RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1277 | { |
1278 | bool baseIsSuper = m_base->isSuperNode(); |
1279 | bool subscriptIsNonIndexString = isNonIndexStringElement(*m_subscript); |
1280 | |
1281 | RefPtr<RegisterID> base; |
1282 | if (baseIsSuper) |
1283 | base = emitSuperBaseForCallee(generator); |
1284 | else { |
1285 | if (subscriptIsNonIndexString) |
1286 | base = generator.emitNode(m_base); |
1287 | else |
1288 | base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); |
1289 | } |
1290 | |
1291 | RefPtr<RegisterID> function; |
1292 | RefPtr<RegisterID> thisRegister; |
1293 | if (baseIsSuper) { |
1294 | // Note that we only need to do this once because we either have a non-TDZ this or we throw. Once we have a non-TDZ this, we can't change its value back to TDZ. |
1295 | thisRegister = generator.ensureThis(); |
1296 | } |
1297 | if (subscriptIsNonIndexString) { |
1298 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
1299 | if (baseIsSuper) |
1300 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisRegister.get(), static_cast<StringNode*>(m_subscript)->value()); |
1301 | else |
1302 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value()); |
1303 | } else { |
1304 | RefPtr<RegisterID> property = generator.emitNodeForProperty(m_subscript); |
1305 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
1306 | if (baseIsSuper) |
1307 | function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisRegister.get(), property.get()); |
1308 | else |
1309 | function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
1310 | } |
1311 | |
1312 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
1313 | CallArguments callArguments(generator, m_args); |
1314 | if (baseIsSuper) { |
1315 | generator.emitTDZCheck(generator.thisRegister()); |
1316 | generator.move(callArguments.thisRegister(), thisRegister.get()); |
1317 | } else |
1318 | generator.move(callArguments.thisRegister(), base.get()); |
1319 | RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1320 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
1321 | return ret; |
1322 | } |
1323 | |
1324 | // ------------------------------ FunctionCallDotNode ---------------------------------- |
1325 | |
1326 | RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1327 | { |
1328 | RefPtr<RegisterID> function = generator.tempDestination(dst); |
1329 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); |
1330 | CallArguments callArguments(generator, m_args); |
1331 | bool baseIsSuper = m_base->isSuperNode(); |
1332 | if (baseIsSuper) |
1333 | generator.move(callArguments.thisRegister(), generator.ensureThis()); |
1334 | else |
1335 | generator.emitNode(callArguments.thisRegister(), m_base); |
1336 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
1337 | if (baseIsSuper) { |
1338 | RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator); |
1339 | generator.emitGetById(function.get(), superBase.get(), callArguments.thisRegister(), m_ident); |
1340 | } else |
1341 | generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); |
1342 | RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1343 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
1344 | return ret; |
1345 | } |
1346 | |
1347 | static constexpr size_t maxDistanceToInnermostCallOrApply = 2; |
1348 | |
1349 | RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1350 | { |
1351 | RefPtr<RegisterID> base = generator.emitNode(m_base); |
1352 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
1353 | RefPtr<RegisterID> function; |
1354 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst); |
1355 | |
1356 | auto makeFunction = [&] { |
1357 | if (m_base->isSuperNode()) { |
1358 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
1359 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().callPublicName()); |
1360 | } else |
1361 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName()); |
1362 | }; |
1363 | |
1364 | bool emitCallCheck = !generator.isBuiltinFunction(); |
1365 | if (m_distanceToInnermostCallOrApply > maxDistanceToInnermostCallOrApply && emitCallCheck) { |
1366 | makeFunction(); |
1367 | CallArguments callArguments(generator, m_args); |
1368 | generator.move(callArguments.thisRegister(), base.get()); |
1369 | generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1370 | generator.move(dst, returnValue.get()); |
1371 | return returnValue.get(); |
1372 | } |
1373 | |
1374 | Ref<Label> realCall = generator.newLabel(); |
1375 | Ref<Label> end = generator.newLabel(); |
1376 | |
1377 | if (emitCallCheck) { |
1378 | makeFunction(); |
1379 | generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); |
1380 | } |
1381 | { |
1382 | if (m_args->m_listNode && m_args->m_listNode->m_expr && m_args->m_listNode->m_expr->isSpreadExpression()) { |
1383 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); |
1384 | ExpressionNode* subject = spread->expression(); |
1385 | RefPtr<RegisterID> argumentsRegister; |
1386 | argumentsRegister = generator.emitNode(subject); |
1387 | generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); |
1388 | RefPtr<RegisterID> thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); |
1389 | generator.emitCallVarargsInTailPosition(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1390 | } else if (m_args->m_listNode && m_args->m_listNode->m_expr) { |
1391 | ArgumentListNode* oldList = m_args->m_listNode; |
1392 | m_args->m_listNode = m_args->m_listNode->m_next; |
1393 | |
1394 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1395 | CallArguments callArguments(generator, m_args); |
1396 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
1397 | generator.emitCallInTailPosition(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1398 | m_args->m_listNode = oldList; |
1399 | } else { |
1400 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1401 | CallArguments callArguments(generator, m_args); |
1402 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
1403 | generator.emitCallInTailPosition(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1404 | } |
1405 | } |
1406 | if (emitCallCheck) { |
1407 | generator.emitJump(end.get()); |
1408 | generator.emitLabel(realCall.get()); |
1409 | { |
1410 | CallArguments callArguments(generator, m_args); |
1411 | generator.move(callArguments.thisRegister(), base.get()); |
1412 | generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1413 | } |
1414 | generator.emitLabel(end.get()); |
1415 | } |
1416 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
1417 | return returnValue.get(); |
1418 | } |
1419 | |
1420 | static bool areTrivialApplyArguments(ArgumentsNode* args) |
1421 | { |
1422 | return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next |
1423 | || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); |
1424 | } |
1425 | |
1426 | RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1427 | { |
1428 | // A few simple cases can be trivially handled as ordinary function calls. |
1429 | // function.apply(), function.apply(arg) -> identical to function.call |
1430 | // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation |
1431 | bool mayBeCall = areTrivialApplyArguments(m_args); |
1432 | |
1433 | RefPtr<RegisterID> function; |
1434 | RefPtr<RegisterID> base = generator.emitNode(m_base); |
1435 | RefPtr<RegisterID> returnValue = generator.finalDestination(dst); |
1436 | auto makeFunction = [&] { |
1437 | if (m_base->isSuperNode()) { |
1438 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
1439 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().applyPublicName()); |
1440 | } else |
1441 | function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName()); |
1442 | }; |
1443 | |
1444 | bool emitCallCheck = !generator.isBuiltinFunction(); |
1445 | if (m_distanceToInnermostCallOrApply > maxDistanceToInnermostCallOrApply && emitCallCheck) { |
1446 | makeFunction(); |
1447 | CallArguments callArguments(generator, m_args); |
1448 | generator.move(callArguments.thisRegister(), base.get()); |
1449 | generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1450 | generator.move(dst, returnValue.get()); |
1451 | return returnValue.get(); |
1452 | } |
1453 | |
1454 | Ref<Label> realCall = generator.newLabel(); |
1455 | Ref<Label> end = generator.newLabel(); |
1456 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
1457 | if (emitCallCheck) { |
1458 | makeFunction(); |
1459 | ASSERT(!m_base->isResolveNode() || static_cast<ResolveNode*>(m_base)->identifier() != "Reflect" ); |
1460 | generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); |
1461 | } |
1462 | if (mayBeCall) { |
1463 | if (m_args->m_listNode && m_args->m_listNode->m_expr) { |
1464 | ArgumentListNode* oldList = m_args->m_listNode; |
1465 | if (m_args->m_listNode->m_expr->isSpreadExpression()) { |
1466 | SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); |
1467 | RefPtr<RegisterID> realFunction = generator.move(generator.newTemporary(), base.get()); |
1468 | RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(0)); |
1469 | RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); |
1470 | RefPtr<RegisterID> argumentsRegister = generator.emitLoad(generator.newTemporary(), jsUndefined()); |
1471 | |
1472 | auto = scopedLambda<void(BytecodeGenerator&, RegisterID*)>([&thisRegister, &argumentsRegister, &index](BytecodeGenerator& generator, RegisterID* value) |
1473 | { |
1474 | Ref<Label> haveThis = generator.newLabel(); |
1475 | Ref<Label> end = generator.newLabel(); |
1476 | RefPtr<RegisterID> compareResult = generator.newTemporary(); |
1477 | RefPtr<RegisterID> indexZeroCompareResult = generator.emitBinaryOp<OpEq>(compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(0)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); |
1478 | generator.emitJumpIfFalse(indexZeroCompareResult.get(), haveThis.get()); |
1479 | generator.move(thisRegister.get(), value); |
1480 | generator.emitLoad(index.get(), jsNumber(1)); |
1481 | generator.emitJump(end.get()); |
1482 | generator.emitLabel(haveThis.get()); |
1483 | RefPtr<RegisterID> indexOneCompareResult = generator.emitBinaryOp<OpEq>(compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(1)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); |
1484 | generator.emitJumpIfFalse(indexOneCompareResult.get(), end.get()); |
1485 | generator.move(argumentsRegister.get(), value); |
1486 | generator.emitLoad(index.get(), jsNumber(2)); |
1487 | generator.emitLabel(end.get()); |
1488 | }); |
1489 | generator.emitEnumeration(this, spread->expression(), extractor); |
1490 | generator.emitCallVarargsInTailPosition(returnValue.get(), realFunction.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 0, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1491 | } else if (m_args->m_listNode->m_next) { |
1492 | ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); |
1493 | ASSERT(!m_args->m_listNode->m_next->m_next); |
1494 | m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.parserArena(), 0, 0); |
1495 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1496 | CallArguments callArguments(generator, m_args); |
1497 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
1498 | generator.emitCallInTailPosition(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1499 | } else { |
1500 | m_args->m_listNode = m_args->m_listNode->m_next; |
1501 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1502 | CallArguments callArguments(generator, m_args); |
1503 | generator.emitNode(callArguments.thisRegister(), oldList->m_expr); |
1504 | generator.emitCallInTailPosition(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1505 | } |
1506 | m_args->m_listNode = oldList; |
1507 | } else { |
1508 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1509 | CallArguments callArguments(generator, m_args); |
1510 | generator.emitLoad(callArguments.thisRegister(), jsUndefined()); |
1511 | generator.emitCallInTailPosition(returnValue.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1512 | } |
1513 | } else { |
1514 | ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); |
1515 | RefPtr<RegisterID> realFunction = generator.move(generator.tempDestination(dst), base.get()); |
1516 | RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr); |
1517 | RefPtr<RegisterID> argsRegister; |
1518 | ArgumentListNode* args = m_args->m_listNode->m_next; |
1519 | argsRegister = generator.emitNode(args->m_expr); |
1520 | |
1521 | // Function.prototype.apply ignores extra arguments, but we still |
1522 | // need to evaluate them for side effects. |
1523 | while ((args = args->m_next)) |
1524 | generator.emitNode(args->m_expr); |
1525 | |
1526 | generator.emitCallVarargsInTailPosition(returnValue.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), 0, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1527 | } |
1528 | if (emitCallCheck) { |
1529 | generator.emitJump(end.get()); |
1530 | generator.emitLabel(realCall.get()); |
1531 | CallArguments callArguments(generator, m_args); |
1532 | generator.move(callArguments.thisRegister(), base.get()); |
1533 | generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); |
1534 | generator.emitLabel(end.get()); |
1535 | } |
1536 | generator.emitProfileType(returnValue.get(), divotStart(), divotEnd()); |
1537 | return returnValue.get(); |
1538 | } |
1539 | |
1540 | // ------------------------------ PostfixNode ---------------------------------- |
1541 | |
1542 | static RegisterID* emitIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) |
1543 | { |
1544 | return (oper == OpPlusPlus) ? generator.emitInc(srcDst) : generator.emitDec(srcDst); |
1545 | } |
1546 | |
1547 | static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) |
1548 | { |
1549 | if (dst == srcDst) |
1550 | return generator.emitToNumber(generator.finalDestination(dst), srcDst); |
1551 | RefPtr<RegisterID> tmp = generator.emitToNumber(generator.tempDestination(dst), srcDst); |
1552 | emitIncOrDec(generator, srcDst, oper); |
1553 | return generator.move(dst, tmp.get()); |
1554 | } |
1555 | |
1556 | RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
1557 | { |
1558 | if (dst == generator.ignoredResult()) |
1559 | return PrefixNode::emitResolve(generator, dst); |
1560 | |
1561 | ASSERT(m_expr->isResolveNode()); |
1562 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); |
1563 | const Identifier& ident = resolve->identifier(); |
1564 | |
1565 | Variable var = generator.variable(ident); |
1566 | if (RegisterID* local = var.local()) { |
1567 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
1568 | RefPtr<RegisterID> localReg = local; |
1569 | if (var.isReadOnly()) { |
1570 | generator.emitReadOnlyExceptionIfNeeded(var); |
1571 | localReg = generator.move(generator.tempDestination(dst), local); |
1572 | } |
1573 | RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); |
1574 | generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd()); |
1575 | return oldValue.get(); |
1576 | } |
1577 | |
1578 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1579 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
1580 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
1581 | generator.emitTDZCheckIfNecessary(var, value.get(), nullptr); |
1582 | if (var.isReadOnly()) { |
1583 | bool threwException = generator.emitReadOnlyExceptionIfNeeded(var); |
1584 | if (threwException) |
1585 | return value.get(); |
1586 | } |
1587 | RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); |
1588 | if (!var.isReadOnly()) { |
1589 | generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound, InitializationMode::NotInitialization); |
1590 | generator.emitProfileType(value.get(), var, divotStart(), divotEnd()); |
1591 | } |
1592 | |
1593 | return oldValue.get(); |
1594 | } |
1595 | |
1596 | RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
1597 | { |
1598 | if (dst == generator.ignoredResult()) |
1599 | return PrefixNode::emitBracket(generator, dst); |
1600 | |
1601 | ASSERT(m_expr->isBracketAccessorNode()); |
1602 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); |
1603 | ExpressionNode* baseNode = bracketAccessor->base(); |
1604 | ExpressionNode* subscript = bracketAccessor->subscript(); |
1605 | |
1606 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); |
1607 | RefPtr<RegisterID> property = generator.emitNodeForProperty(subscript); |
1608 | |
1609 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
1610 | RefPtr<RegisterID> value; |
1611 | RefPtr<RegisterID> thisValue; |
1612 | if (baseNode->isSuperNode()) { |
1613 | thisValue = generator.ensureThis(); |
1614 | value = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get()); |
1615 | } else |
1616 | value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); |
1617 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); |
1618 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1619 | if (baseNode->isSuperNode()) |
1620 | generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value.get()); |
1621 | else |
1622 | generator.emitPutByVal(base.get(), property.get(), value.get()); |
1623 | generator.emitProfileType(value.get(), divotStart(), divotEnd()); |
1624 | return generator.move(dst, oldValue); |
1625 | } |
1626 | |
1627 | RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
1628 | { |
1629 | if (dst == generator.ignoredResult()) |
1630 | return PrefixNode::emitDot(generator, dst); |
1631 | |
1632 | ASSERT(m_expr->isDotAccessorNode()); |
1633 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); |
1634 | ExpressionNode* baseNode = dotAccessor->base(); |
1635 | bool baseIsSuper = baseNode->isSuperNode(); |
1636 | const Identifier& ident = dotAccessor->identifier(); |
1637 | |
1638 | RefPtr<RegisterID> base = generator.emitNode(baseNode); |
1639 | |
1640 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
1641 | RefPtr<RegisterID> value; |
1642 | RefPtr<RegisterID> thisValue; |
1643 | if (baseIsSuper) { |
1644 | thisValue = generator.ensureThis(); |
1645 | value = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), ident); |
1646 | } else |
1647 | value = generator.emitGetById(generator.newTemporary(), base.get(), ident); |
1648 | RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); |
1649 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1650 | if (baseIsSuper) |
1651 | generator.emitPutById(base.get(), thisValue.get(), ident, value.get()); |
1652 | else |
1653 | generator.emitPutById(base.get(), ident, value.get()); |
1654 | generator.emitProfileType(value.get(), divotStart(), divotEnd()); |
1655 | return generator.move(dst, oldValue); |
1656 | } |
1657 | |
1658 | RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1659 | { |
1660 | if (m_expr->isResolveNode()) |
1661 | return emitResolve(generator, dst); |
1662 | |
1663 | if (m_expr->isBracketAccessorNode()) |
1664 | return emitBracket(generator, dst); |
1665 | |
1666 | if (m_expr->isDotAccessorNode()) |
1667 | return emitDot(generator, dst); |
1668 | |
1669 | ASSERT(m_expr->isFunctionCall()); |
1670 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
1671 | ? "Postfix ++ operator applied to value that is not a reference."_s |
1672 | : "Postfix -- operator applied to value that is not a reference."_s ); |
1673 | } |
1674 | |
1675 | // ------------------------------ DeleteResolveNode ----------------------------------- |
1676 | |
1677 | RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1678 | { |
1679 | Variable var = generator.variable(m_ident); |
1680 | if (var.local()) { |
1681 | generator.emitTDZCheckIfNecessary(var, var.local(), nullptr); |
1682 | return generator.emitLoad(generator.finalDestination(dst), false); |
1683 | } |
1684 | |
1685 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1686 | RefPtr<RegisterID> base = generator.emitResolveScope(dst, var); |
1687 | generator.emitTDZCheckIfNecessary(var, nullptr, base.get()); |
1688 | return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident); |
1689 | } |
1690 | |
1691 | // ------------------------------ DeleteBracketNode ----------------------------------- |
1692 | |
1693 | RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1694 | { |
1695 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); |
1696 | RefPtr<RegisterID> r1 = generator.emitNode(m_subscript); |
1697 | |
1698 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1699 | if (m_base->isSuperNode()) |
1700 | return emitThrowReferenceError(generator, "Cannot delete a super property" ); |
1701 | return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get()); |
1702 | } |
1703 | |
1704 | // ------------------------------ DeleteDotNode ----------------------------------- |
1705 | |
1706 | RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1707 | { |
1708 | RefPtr<RegisterID> r0 = generator.emitNode(m_base); |
1709 | |
1710 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1711 | if (m_base->isSuperNode()) |
1712 | return emitThrowReferenceError(generator, "Cannot delete a super property" ); |
1713 | return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident); |
1714 | } |
1715 | |
1716 | // ------------------------------ DeleteValueNode ----------------------------------- |
1717 | |
1718 | RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1719 | { |
1720 | generator.emitNode(generator.ignoredResult(), m_expr); |
1721 | |
1722 | // delete on a non-location expression ignores the value and returns true |
1723 | return generator.emitLoad(generator.finalDestination(dst), true); |
1724 | } |
1725 | |
1726 | // ------------------------------ VoidNode ------------------------------------- |
1727 | |
1728 | RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1729 | { |
1730 | if (dst == generator.ignoredResult()) { |
1731 | generator.emitNode(generator.ignoredResult(), m_expr); |
1732 | return 0; |
1733 | } |
1734 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); |
1735 | return generator.emitLoad(dst, jsUndefined()); |
1736 | } |
1737 | |
1738 | // ------------------------------ TypeOfResolveNode ----------------------------------- |
1739 | |
1740 | RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1741 | { |
1742 | Variable var = generator.variable(m_ident); |
1743 | if (RegisterID* local = var.local()) { |
1744 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
1745 | if (dst == generator.ignoredResult()) |
1746 | return 0; |
1747 | return generator.emitTypeOf(generator.finalDestination(dst), local); |
1748 | } |
1749 | |
1750 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
1751 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); |
1752 | generator.emitTDZCheckIfNecessary(var, value.get(), nullptr); |
1753 | if (dst == generator.ignoredResult()) |
1754 | return 0; |
1755 | return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get()); |
1756 | } |
1757 | |
1758 | // ------------------------------ TypeOfValueNode ----------------------------------- |
1759 | |
1760 | RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1761 | { |
1762 | if (dst == generator.ignoredResult()) { |
1763 | generator.emitNode(generator.ignoredResult(), m_expr); |
1764 | return 0; |
1765 | } |
1766 | RefPtr<RegisterID> src = generator.emitNode(m_expr); |
1767 | return generator.emitTypeOf(generator.finalDestination(dst), src.get()); |
1768 | } |
1769 | |
1770 | // ------------------------------ PrefixNode ---------------------------------- |
1771 | |
1772 | RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* dst) |
1773 | { |
1774 | ASSERT(m_expr->isResolveNode()); |
1775 | ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); |
1776 | const Identifier& ident = resolve->identifier(); |
1777 | |
1778 | Variable var = generator.variable(ident); |
1779 | if (RegisterID* local = var.local()) { |
1780 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
1781 | RefPtr<RegisterID> localReg = local; |
1782 | if (var.isReadOnly()) { |
1783 | generator.emitReadOnlyExceptionIfNeeded(var); |
1784 | localReg = generator.move(generator.tempDestination(dst), localReg.get()); |
1785 | } else if (generator.shouldEmitTypeProfilerHooks()) { |
1786 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); |
1787 | generator.move(tempDst.get(), localReg.get()); |
1788 | emitIncOrDec(generator, tempDst.get(), m_operator); |
1789 | generator.move(localReg.get(), tempDst.get()); |
1790 | generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd()); |
1791 | return generator.move(dst, tempDst.get()); |
1792 | } |
1793 | emitIncOrDec(generator, localReg.get(), m_operator); |
1794 | return generator.move(dst, localReg.get()); |
1795 | } |
1796 | |
1797 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1798 | RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); |
1799 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
1800 | generator.emitTDZCheckIfNecessary(var, value.get(), nullptr); |
1801 | if (var.isReadOnly()) { |
1802 | bool threwException = generator.emitReadOnlyExceptionIfNeeded(var); |
1803 | if (threwException) |
1804 | return value.get(); |
1805 | } |
1806 | |
1807 | emitIncOrDec(generator, value.get(), m_operator); |
1808 | if (!var.isReadOnly()) { |
1809 | generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound, InitializationMode::NotInitialization); |
1810 | generator.emitProfileType(value.get(), var, divotStart(), divotEnd()); |
1811 | } |
1812 | return generator.move(dst, value.get()); |
1813 | } |
1814 | |
1815 | RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* dst) |
1816 | { |
1817 | ASSERT(m_expr->isBracketAccessorNode()); |
1818 | BracketAccessorNode* bracketAccessor = static_cast<BracketAccessorNode*>(m_expr); |
1819 | ExpressionNode* baseNode = bracketAccessor->base(); |
1820 | ExpressionNode* subscript = bracketAccessor->subscript(); |
1821 | |
1822 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(baseNode, bracketAccessor->subscriptHasAssignments(), subscript->isPure(generator)); |
1823 | RefPtr<RegisterID> property = generator.emitNodeForProperty(subscript); |
1824 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
1825 | |
1826 | generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd()); |
1827 | RegisterID* value; |
1828 | RefPtr<RegisterID> thisValue; |
1829 | if (baseNode->isSuperNode()) { |
1830 | thisValue = generator.ensureThis(); |
1831 | value = generator.emitGetByVal(propDst.get(), base.get(), thisValue.get(), property.get()); |
1832 | } else |
1833 | value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); |
1834 | emitIncOrDec(generator, value, m_operator); |
1835 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1836 | if (baseNode->isSuperNode()) |
1837 | generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value); |
1838 | else |
1839 | generator.emitPutByVal(base.get(), property.get(), value); |
1840 | generator.emitProfileType(value, divotStart(), divotEnd()); |
1841 | return generator.move(dst, propDst.get()); |
1842 | } |
1843 | |
1844 | RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) |
1845 | { |
1846 | ASSERT(m_expr->isDotAccessorNode()); |
1847 | DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr); |
1848 | ExpressionNode* baseNode = dotAccessor->base(); |
1849 | const Identifier& ident = dotAccessor->identifier(); |
1850 | |
1851 | RefPtr<RegisterID> base = generator.emitNode(baseNode); |
1852 | RefPtr<RegisterID> propDst = generator.tempDestination(dst); |
1853 | |
1854 | generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd()); |
1855 | RegisterID* value; |
1856 | RefPtr<RegisterID> thisValue; |
1857 | if (baseNode->isSuperNode()) { |
1858 | thisValue = generator.ensureThis(); |
1859 | value = generator.emitGetById(propDst.get(), base.get(), thisValue.get(), ident); |
1860 | } else |
1861 | value = generator.emitGetById(propDst.get(), base.get(), ident); |
1862 | emitIncOrDec(generator, value, m_operator); |
1863 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
1864 | if (baseNode->isSuperNode()) |
1865 | generator.emitPutById(base.get(), thisValue.get(), ident, value); |
1866 | else |
1867 | generator.emitPutById(base.get(), ident, value); |
1868 | generator.emitProfileType(value, divotStart(), divotEnd()); |
1869 | return generator.move(dst, propDst.get()); |
1870 | } |
1871 | |
1872 | RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1873 | { |
1874 | if (m_expr->isResolveNode()) |
1875 | return emitResolve(generator, dst); |
1876 | |
1877 | if (m_expr->isBracketAccessorNode()) |
1878 | return emitBracket(generator, dst); |
1879 | |
1880 | if (m_expr->isDotAccessorNode()) |
1881 | return emitDot(generator, dst); |
1882 | |
1883 | ASSERT(m_expr->isFunctionCall()); |
1884 | return emitThrowReferenceError(generator, m_operator == OpPlusPlus |
1885 | ? "Prefix ++ operator applied to value that is not a reference."_s |
1886 | : "Prefix -- operator applied to value that is not a reference."_s ); |
1887 | } |
1888 | |
1889 | // ------------------------------ Unary Operation Nodes ----------------------------------- |
1890 | |
1891 | RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1892 | { |
1893 | RefPtr<RegisterID> src = generator.emitNode(m_expr); |
1894 | generator.emitExpressionInfo(position(), position(), position()); |
1895 | return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get(), OperandTypes(m_expr->resultDescriptor())); |
1896 | } |
1897 | |
1898 | // ------------------------------ UnaryPlusNode ----------------------------------- |
1899 | |
1900 | RegisterID* UnaryPlusNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
1901 | { |
1902 | ASSERT(opcodeID() == op_to_number); |
1903 | RefPtr<RegisterID> src = generator.emitNode(expr()); |
1904 | generator.emitExpressionInfo(position(), position(), position()); |
1905 | return generator.emitToNumber(generator.finalDestination(dst), src.get()); |
1906 | } |
1907 | |
1908 | // ------------------------------ LogicalNotNode ----------------------------------- |
1909 | |
1910 | void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
1911 | { |
1912 | if (UNLIKELY(needsDebugHook())) |
1913 | generator.emitDebugHook(this); |
1914 | |
1915 | // Reverse the true and false targets. |
1916 | generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode)); |
1917 | } |
1918 | |
1919 | |
1920 | // ------------------------------ Binary Operation Nodes ----------------------------------- |
1921 | |
1922 | // BinaryOpNode::emitStrcat: |
1923 | // |
1924 | // This node generates an op_strcat operation. This opcode can handle concatenation of three or |
1925 | // more values, where we can determine a set of separate op_add operations would be operating on |
1926 | // string values. |
1927 | // |
1928 | // This function expects to be operating on a graph of AST nodes looking something like this: |
1929 | // |
1930 | // (a)... (b) |
1931 | // \ / |
1932 | // (+) (c) |
1933 | // \ / |
1934 | // [d] ((+)) |
1935 | // \ / |
1936 | // [+=] |
1937 | // |
1938 | // The assignment operation is optional, if it exists the register holding the value on the |
1939 | // lefthand side of the assignment should be passing as the optional 'lhs' argument. |
1940 | // |
1941 | // The method should be called on the node at the root of the tree of regular binary add |
1942 | // operations (marked in the diagram with a double set of parentheses). This node must |
1943 | // be performing a string concatenation (determined by statically detecting that at least |
1944 | // one child must be a string). |
1945 | // |
1946 | // Since the minimum number of values being concatenated together is expected to be 3, if |
1947 | // a lhs to a concatenating assignment is not provided then the root add should have at |
1948 | // least one left child that is also an add that can be determined to be operating on strings. |
1949 | // |
1950 | RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) |
1951 | { |
1952 | ASSERT(isAdd()); |
1953 | ASSERT(resultDescriptor().definitelyIsString()); |
1954 | |
1955 | // Create a list of expressions for all the adds in the tree of nodes we can convert into |
1956 | // a string concatenation. The rightmost node (c) is added first. The rightmost node is |
1957 | // added first, and the leftmost child is never added, so the vector produced for the |
1958 | // example above will be [ c, b ]. |
1959 | Vector<ExpressionNode*, 16> reverseExpressionList; |
1960 | reverseExpressionList.append(m_expr2); |
1961 | |
1962 | // Examine the left child of the add. So long as this is a string add, add its right-child |
1963 | // to the list, and keep processing along the left fork. |
1964 | ExpressionNode* leftMostAddChild = m_expr1; |
1965 | while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { |
1966 | reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); |
1967 | leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; |
1968 | } |
1969 | |
1970 | Vector<RefPtr<RegisterID>, 16> temporaryRegisters; |
1971 | |
1972 | // If there is an assignment, allocate a temporary to hold the lhs after conversion. |
1973 | // We could possibly avoid this (the lhs is converted last anyway, we could let the |
1974 | // op_strcat node handle its conversion if required). |
1975 | if (lhs) |
1976 | temporaryRegisters.append(generator.newTemporary()); |
1977 | |
1978 | // Emit code for the leftmost node ((a) in the example). |
1979 | temporaryRegisters.append(generator.newTemporary()); |
1980 | RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); |
1981 | generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); |
1982 | |
1983 | // Note on ordering of conversions: |
1984 | // |
1985 | // We maintain the same ordering of conversions as we would see if the concatenations |
1986 | // was performed as a sequence of adds (otherwise this optimization could change |
1987 | // behaviour should an object have been provided a valueOf or toString method). |
1988 | // |
1989 | // Considering the above example, the sequnce of execution is: |
1990 | // * evaluate operand (a) |
1991 | // * evaluate operand (b) |
1992 | // * convert (a) to primitive <- (this would be triggered by the first add) |
1993 | // * convert (b) to primitive <- (ditto) |
1994 | // * evaluate operand (c) |
1995 | // * convert (c) to primitive <- (this would be triggered by the second add) |
1996 | // And optionally, if there is an assignment: |
1997 | // * convert (d) to primitive <- (this would be triggered by the assigning addition) |
1998 | // |
1999 | // As such we do not plant an op to convert the leftmost child now. Instead, use |
2000 | // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion |
2001 | // once the second node has been generated. However, if the leftmost child is an |
2002 | // immediate we can trivially determine that no conversion will be required. |
2003 | // If this is the case |
2004 | if (leftMostAddChild->isString()) |
2005 | leftMostAddChildTempRegister = 0; |
2006 | |
2007 | while (reverseExpressionList.size()) { |
2008 | ExpressionNode* node = reverseExpressionList.last(); |
2009 | reverseExpressionList.removeLast(); |
2010 | |
2011 | // Emit the code for the current node. |
2012 | temporaryRegisters.append(generator.newTemporary()); |
2013 | generator.emitNode(temporaryRegisters.last().get(), node); |
2014 | |
2015 | // On the first iteration of this loop, when we first reach this point we have just |
2016 | // generated the second node, which means it is time to convert the leftmost operand. |
2017 | if (leftMostAddChildTempRegister) { |
2018 | generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); |
2019 | leftMostAddChildTempRegister = 0; // Only do this once. |
2020 | } |
2021 | // Plant a conversion for this node, if necessary. |
2022 | if (!node->isString()) |
2023 | generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); |
2024 | } |
2025 | ASSERT(temporaryRegisters.size() >= 3); |
2026 | |
2027 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. |
2028 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. |
2029 | if (emitExpressionInfoForMe) |
2030 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
2031 | // If there is an assignment convert the lhs now. This will also copy lhs to |
2032 | // the temporary register we allocated for it. |
2033 | if (lhs) |
2034 | generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); |
2035 | |
2036 | return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); |
2037 | } |
2038 | |
2039 | void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
2040 | { |
2041 | TriState branchCondition; |
2042 | ExpressionNode* branchExpression; |
2043 | tryFoldToBranch(generator, branchCondition, branchExpression); |
2044 | |
2045 | if (UNLIKELY(needsDebugHook())) { |
2046 | if (branchCondition != MixedTriState) |
2047 | generator.emitDebugHook(this); |
2048 | } |
2049 | |
2050 | if (branchCondition == MixedTriState) |
2051 | ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); |
2052 | else if (branchCondition == TrueTriState) |
2053 | generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode); |
2054 | else |
2055 | generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode)); |
2056 | } |
2057 | |
2058 | static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant) |
2059 | { |
2060 | ResultType expressionType = branchExpression->resultDescriptor(); |
2061 | |
2062 | if (expressionType.definitelyIsBoolean() && constant.isBoolean()) |
2063 | return true; |
2064 | else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1)) |
2065 | return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch. |
2066 | else if (expressionType.isInt32() && constant.isInt32() && constant.asInt32() == 0) |
2067 | return true; |
2068 | |
2069 | return false; |
2070 | } |
2071 | |
2072 | void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression) |
2073 | { |
2074 | branchCondition = MixedTriState; |
2075 | branchExpression = 0; |
2076 | |
2077 | ConstantNode* constant = 0; |
2078 | if (m_expr1->isConstant()) { |
2079 | constant = static_cast<ConstantNode*>(m_expr1); |
2080 | branchExpression = m_expr2; |
2081 | } else if (m_expr2->isConstant()) { |
2082 | constant = static_cast<ConstantNode*>(m_expr2); |
2083 | branchExpression = m_expr1; |
2084 | } |
2085 | |
2086 | if (!constant) |
2087 | return; |
2088 | ASSERT(branchExpression); |
2089 | |
2090 | OpcodeID opcodeID = this->opcodeID(); |
2091 | JSValue value = constant->jsValue(generator); |
2092 | bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value); |
2093 | if (!canFoldToBranch) |
2094 | return; |
2095 | |
2096 | if (opcodeID == op_eq || opcodeID == op_stricteq) |
2097 | branchCondition = triState(value.pureToBoolean()); |
2098 | else if (opcodeID == op_neq || opcodeID == op_nstricteq) |
2099 | branchCondition = triState(!value.pureToBoolean()); |
2100 | } |
2101 | |
2102 | RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2103 | { |
2104 | OpcodeID opcodeID = this->opcodeID(); |
2105 | |
2106 | if (opcodeID == op_less || opcodeID == op_lesseq || opcodeID == op_greater || opcodeID == op_greatereq) { |
2107 | auto isUInt32 = [&] (ExpressionNode* node) -> Optional<UInt32Result> { |
2108 | if (node->isBinaryOpNode() && static_cast<BinaryOpNode*>(node)->opcodeID() == op_urshift) |
2109 | return UInt32Result::UInt32; |
2110 | if (node->isNumber() && static_cast<NumberNode*>(node)->isIntegerNode()) { |
2111 | auto value = jsNumber(static_cast<NumberNode*>(node)->value()); |
2112 | if (value.isInt32() && value.asInt32() >= 0) |
2113 | return UInt32Result::Constant; |
2114 | } |
2115 | return WTF::nullopt; |
2116 | }; |
2117 | auto leftResult = isUInt32(m_expr1); |
2118 | auto rightResult = isUInt32(m_expr2); |
2119 | if ((leftResult && rightResult) && (leftResult.value() == UInt32Result::UInt32 || rightResult.value() == UInt32Result::UInt32)) { |
2120 | auto* left = m_expr1; |
2121 | auto* right = m_expr2; |
2122 | if (left->isBinaryOpNode()) { |
2123 | ASSERT(static_cast<BinaryOpNode*>(left)->opcodeID() == op_urshift); |
2124 | static_cast<BinaryOpNode*>(left)->m_shouldToUnsignedResult = false; |
2125 | } |
2126 | if (right->isBinaryOpNode()) { |
2127 | ASSERT(static_cast<BinaryOpNode*>(right)->opcodeID() == op_urshift); |
2128 | static_cast<BinaryOpNode*>(right)->m_shouldToUnsignedResult = false; |
2129 | } |
2130 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); |
2131 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
2132 | generator.emitExpressionInfo(position(), position(), position()); |
2133 | |
2134 | // Since the both sides only accept Int32, replacing operands is not observable to users. |
2135 | bool replaceOperands = false; |
2136 | OpcodeID resultOp = opcodeID; |
2137 | switch (opcodeID) { |
2138 | case op_less: |
2139 | resultOp = op_below; |
2140 | break; |
2141 | case op_lesseq: |
2142 | resultOp = op_beloweq; |
2143 | break; |
2144 | case op_greater: |
2145 | resultOp = op_below; |
2146 | replaceOperands = true; |
2147 | break; |
2148 | case op_greatereq: |
2149 | resultOp = op_beloweq; |
2150 | replaceOperands = true; |
2151 | break; |
2152 | default: |
2153 | RELEASE_ASSERT_NOT_REACHED(); |
2154 | } |
2155 | OperandTypes operandTypes(left->resultDescriptor(), right->resultDescriptor()); |
2156 | if (replaceOperands) { |
2157 | std::swap(src1, src2); |
2158 | operandTypes = OperandTypes(right->resultDescriptor(), left->resultDescriptor()); |
2159 | } |
2160 | return generator.emitBinaryOp(resultOp, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), operandTypes); |
2161 | } |
2162 | } |
2163 | |
2164 | if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) { |
2165 | generator.emitExpressionInfo(position(), position(), position()); |
2166 | return emitStrcat(generator, dst); |
2167 | } |
2168 | |
2169 | if (opcodeID == op_neq) { |
2170 | if (m_expr1->isNull() || m_expr2->isNull()) { |
2171 | RefPtr<RegisterID> src = generator.tempDestination(dst); |
2172 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); |
2173 | return generator.emitUnaryOp<OpNeqNull>(generator.finalDestination(dst, src.get()), src.get()); |
2174 | } |
2175 | } |
2176 | |
2177 | ExpressionNode* left = m_expr1; |
2178 | ExpressionNode* right = m_expr2; |
2179 | if (opcodeID == op_neq || opcodeID == op_nstricteq) { |
2180 | if (left->isString()) |
2181 | std::swap(left, right); |
2182 | } |
2183 | |
2184 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); |
2185 | bool wasTypeof = generator.lastOpcodeID() == op_typeof; |
2186 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
2187 | generator.emitExpressionInfo(position(), position(), position()); |
2188 | if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { |
2189 | RefPtr<RegisterID> tmp = generator.tempDestination(dst); |
2190 | if (opcodeID == op_neq) |
2191 | generator.emitEqualityOp<OpEq>(generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
2192 | else if (opcodeID == op_nstricteq) |
2193 | generator.emitEqualityOp<OpStricteq>(generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get()); |
2194 | else |
2195 | RELEASE_ASSERT_NOT_REACHED(); |
2196 | return generator.emitUnaryOp<OpNot>(generator.finalDestination(dst, tmp.get()), tmp.get()); |
2197 | } |
2198 | RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor())); |
2199 | if (m_shouldToUnsignedResult) { |
2200 | if (opcodeID == op_urshift && dst != generator.ignoredResult()) |
2201 | return generator.emitUnaryOp<OpUnsigned>(result, result); |
2202 | } |
2203 | return result; |
2204 | } |
2205 | |
2206 | RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2207 | { |
2208 | if (m_expr1->isNull() || m_expr2->isNull()) { |
2209 | RefPtr<RegisterID> src = generator.tempDestination(dst); |
2210 | generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); |
2211 | return generator.emitUnaryOp<OpEqNull>(generator.finalDestination(dst, src.get()), src.get()); |
2212 | } |
2213 | |
2214 | ExpressionNode* left = m_expr1; |
2215 | ExpressionNode* right = m_expr2; |
2216 | if (left->isString()) |
2217 | std::swap(left, right); |
2218 | |
2219 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); |
2220 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
2221 | return generator.emitEqualityOp<OpEq>(generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); |
2222 | } |
2223 | |
2224 | RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2225 | { |
2226 | ExpressionNode* left = m_expr1; |
2227 | ExpressionNode* right = m_expr2; |
2228 | if (left->isString()) |
2229 | std::swap(left, right); |
2230 | |
2231 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator)); |
2232 | RefPtr<RegisterID> src2 = generator.emitNode(right); |
2233 | return generator.emitEqualityOp<OpStricteq>(generator.finalDestination(dst, src1.get()), src1.get(), src2.get()); |
2234 | } |
2235 | |
2236 | RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2237 | { |
2238 | RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
2239 | RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); |
2240 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2241 | return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); |
2242 | } |
2243 | |
2244 | RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2245 | { |
2246 | RefPtr<RegisterID> hasInstanceValue = generator.newTemporary(); |
2247 | RefPtr<RegisterID> isObject = generator.newTemporary(); |
2248 | RefPtr<RegisterID> isCustom = generator.newTemporary(); |
2249 | RefPtr<RegisterID> prototype = generator.newTemporary(); |
2250 | RefPtr<RegisterID> value = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
2251 | RefPtr<RegisterID> constructor = generator.emitNode(m_expr2); |
2252 | RefPtr<RegisterID> dstReg = generator.finalDestination(dst, value.get()); |
2253 | Ref<Label> custom = generator.newLabel(); |
2254 | Ref<Label> done = generator.newLabel(); |
2255 | Ref<Label> typeError = generator.newLabel(); |
2256 | |
2257 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2258 | generator.emitIsObject(isObject.get(), constructor.get()); |
2259 | generator.emitJumpIfFalse(isObject.get(), typeError.get()); |
2260 | |
2261 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2262 | generator.emitGetById(hasInstanceValue.get(), constructor.get(), generator.vm()->propertyNames->hasInstanceSymbol); |
2263 | |
2264 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2265 | generator.emitOverridesHasInstance(isCustom.get(), constructor.get(), hasInstanceValue.get()); |
2266 | |
2267 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2268 | generator.emitJumpIfTrue(isCustom.get(), custom.get()); |
2269 | |
2270 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2271 | generator.emitGetById(prototype.get(), constructor.get(), generator.vm()->propertyNames->prototype); |
2272 | |
2273 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2274 | generator.emitInstanceOf(dstReg.get(), value.get(), prototype.get()); |
2275 | |
2276 | generator.emitJump(done.get()); |
2277 | |
2278 | generator.emitLabel(typeError.get()); |
2279 | generator.emitThrowTypeError("Right hand side of instanceof is not an object" ); |
2280 | |
2281 | generator.emitLabel(custom.get()); |
2282 | |
2283 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2284 | generator.emitInstanceOfCustom(dstReg.get(), value.get(), constructor.get(), hasInstanceValue.get()); |
2285 | |
2286 | generator.emitLabel(done.get()); |
2287 | |
2288 | return dstReg.get(); |
2289 | } |
2290 | |
2291 | // ------------------------------ InNode ---------------------------- |
2292 | |
2293 | RegisterID* InNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2294 | { |
2295 | if (isNonIndexStringElement(*m_expr1)) { |
2296 | RefPtr<RegisterID> base = generator.emitNode(m_expr2); |
2297 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2298 | return generator.emitInById(generator.finalDestination(dst, base.get()), base.get(), static_cast<StringNode*>(m_expr1)->value()); |
2299 | } |
2300 | |
2301 | RefPtr<RegisterID> key = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); |
2302 | RefPtr<RegisterID> base = generator.emitNode(m_expr2); |
2303 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2304 | return generator.emitInByVal(generator.finalDestination(dst, key.get()), key.get(), base.get()); |
2305 | } |
2306 | |
2307 | |
2308 | // ------------------------------ LogicalOpNode ---------------------------- |
2309 | |
2310 | RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2311 | { |
2312 | RefPtr<RegisterID> temp = generator.tempDestination(dst); |
2313 | Ref<Label> target = generator.newLabel(); |
2314 | |
2315 | generator.emitNode(temp.get(), m_expr1); |
2316 | if (m_operator == OpLogicalAnd) |
2317 | generator.emitJumpIfFalse(temp.get(), target.get()); |
2318 | else |
2319 | generator.emitJumpIfTrue(temp.get(), target.get()); |
2320 | generator.emitNodeInTailPosition(temp.get(), m_expr2); |
2321 | generator.emitLabel(target.get()); |
2322 | |
2323 | return generator.move(dst, temp.get()); |
2324 | } |
2325 | |
2326 | void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
2327 | { |
2328 | if (UNLIKELY(needsDebugHook())) |
2329 | generator.emitDebugHook(this); |
2330 | |
2331 | Ref<Label> afterExpr1 = generator.newLabel(); |
2332 | if (m_operator == OpLogicalAnd) |
2333 | generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, FallThroughMeansTrue); |
2334 | else |
2335 | generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), FallThroughMeansFalse); |
2336 | generator.emitLabel(afterExpr1.get()); |
2337 | |
2338 | generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMode); |
2339 | } |
2340 | |
2341 | // ------------------------------ ConditionalNode ------------------------------ |
2342 | |
2343 | RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2344 | { |
2345 | RefPtr<RegisterID> newDst = generator.finalDestination(dst); |
2346 | Ref<Label> beforeElse = generator.newLabel(); |
2347 | Ref<Label> afterElse = generator.newLabel(); |
2348 | |
2349 | Ref<Label> beforeThen = generator.newLabel(); |
2350 | generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); |
2351 | generator.emitLabel(beforeThen.get()); |
2352 | |
2353 | generator.emitProfileControlFlow(m_expr1->startOffset()); |
2354 | generator.emitNodeInTailPosition(newDst.get(), m_expr1); |
2355 | generator.emitJump(afterElse.get()); |
2356 | |
2357 | generator.emitLabel(beforeElse.get()); |
2358 | generator.emitProfileControlFlow(m_expr1->endOffset() + 1); |
2359 | generator.emitNodeInTailPosition(newDst.get(), m_expr2); |
2360 | |
2361 | generator.emitLabel(afterElse.get()); |
2362 | |
2363 | generator.emitProfileControlFlow(m_expr2->endOffset() + 1); |
2364 | |
2365 | return newDst.get(); |
2366 | } |
2367 | |
2368 | // ------------------------------ ReadModifyResolveNode ----------------------------------- |
2369 | |
2370 | // FIXME: should this be moved to be a method on BytecodeGenerator? |
2371 | static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) |
2372 | { |
2373 | OpcodeID opcodeID; |
2374 | switch (oper) { |
2375 | case OpMultEq: |
2376 | opcodeID = op_mul; |
2377 | break; |
2378 | case OpDivEq: |
2379 | opcodeID = op_div; |
2380 | break; |
2381 | case OpPlusEq: |
2382 | if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) |
2383 | return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); |
2384 | opcodeID = op_add; |
2385 | break; |
2386 | case OpMinusEq: |
2387 | opcodeID = op_sub; |
2388 | break; |
2389 | case OpLShift: |
2390 | opcodeID = op_lshift; |
2391 | break; |
2392 | case OpRShift: |
2393 | opcodeID = op_rshift; |
2394 | break; |
2395 | case OpURShift: |
2396 | opcodeID = op_urshift; |
2397 | break; |
2398 | case OpAndEq: |
2399 | opcodeID = op_bitand; |
2400 | break; |
2401 | case OpXOrEq: |
2402 | opcodeID = op_bitxor; |
2403 | break; |
2404 | case OpOrEq: |
2405 | opcodeID = op_bitor; |
2406 | break; |
2407 | case OpModEq: |
2408 | opcodeID = op_mod; |
2409 | break; |
2410 | case OpPowEq: |
2411 | opcodeID = op_pow; |
2412 | break; |
2413 | default: |
2414 | RELEASE_ASSERT_NOT_REACHED(); |
2415 | return dst; |
2416 | } |
2417 | |
2418 | RegisterID* src2 = generator.emitNode(m_right); |
2419 | |
2420 | // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. |
2421 | // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. |
2422 | if (emitExpressionInfoForMe) |
2423 | generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->divotStart(), emitExpressionInfoForMe->divotEnd()); |
2424 | RegisterID* result = generator.emitBinaryOp(opcodeID, dst, src1, src2, types); |
2425 | if (oper == OpURShift) |
2426 | return generator.emitUnaryOp<OpUnsigned>(result, result); |
2427 | return result; |
2428 | } |
2429 | |
2430 | RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2431 | { |
2432 | JSTextPosition newDivot = divotStart() + m_ident.length(); |
2433 | Variable var = generator.variable(m_ident); |
2434 | if (RegisterID* local = var.local()) { |
2435 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
2436 | if (var.isReadOnly()) { |
2437 | generator.emitReadOnlyExceptionIfNeeded(var); |
2438 | RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
2439 | generator.emitProfileType(result, divotStart(), divotEnd()); |
2440 | return result; |
2441 | } |
2442 | |
2443 | if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { |
2444 | RefPtr<RegisterID> result = generator.newTemporary(); |
2445 | generator.move(result.get(), local); |
2446 | emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
2447 | generator.move(local, result.get()); |
2448 | generator.emitProfileType(local, divotStart(), divotEnd()); |
2449 | return generator.move(dst, result.get()); |
2450 | } |
2451 | |
2452 | RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); |
2453 | generator.emitProfileType(result, divotStart(), divotEnd()); |
2454 | return generator.move(dst, result); |
2455 | } |
2456 | |
2457 | generator.emitExpressionInfo(newDivot, divotStart(), newDivot); |
2458 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
2459 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
2460 | generator.emitTDZCheckIfNecessary(var, value.get(), nullptr); |
2461 | if (var.isReadOnly()) { |
2462 | bool threwException = generator.emitReadOnlyExceptionIfNeeded(var); |
2463 | if (threwException) |
2464 | return value.get(); |
2465 | } |
2466 | RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); |
2467 | RegisterID* returnResult = result.get(); |
2468 | if (!var.isReadOnly()) { |
2469 | returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound, InitializationMode::NotInitialization); |
2470 | generator.emitProfileType(result.get(), var, divotStart(), divotEnd()); |
2471 | } |
2472 | return returnResult; |
2473 | } |
2474 | |
2475 | static InitializationMode initializationModeForAssignmentContext(AssignmentContext assignmentContext) |
2476 | { |
2477 | switch (assignmentContext) { |
2478 | case AssignmentContext::DeclarationStatement: |
2479 | return InitializationMode::Initialization; |
2480 | case AssignmentContext::ConstDeclarationStatement: |
2481 | return InitializationMode::ConstInitialization; |
2482 | case AssignmentContext::AssignmentExpression: |
2483 | return InitializationMode::NotInitialization; |
2484 | } |
2485 | |
2486 | ASSERT_NOT_REACHED(); |
2487 | return InitializationMode::NotInitialization; |
2488 | } |
2489 | |
2490 | // ------------------------------ AssignResolveNode ----------------------------------- |
2491 | |
2492 | RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2493 | { |
2494 | Variable var = generator.variable(m_ident); |
2495 | bool isReadOnly = var.isReadOnly() && m_assignmentContext != AssignmentContext::ConstDeclarationStatement; |
2496 | if (RegisterID* local = var.local()) { |
2497 | RegisterID* result = nullptr; |
2498 | if (m_assignmentContext == AssignmentContext::AssignmentExpression) |
2499 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
2500 | |
2501 | if (isReadOnly) { |
2502 | result = generator.emitNode(dst, m_right); // Execute side effects first. |
2503 | generator.emitReadOnlyExceptionIfNeeded(var); |
2504 | generator.emitProfileType(result, var, divotStart(), divotEnd()); |
2505 | } else if (var.isSpecial()) { |
2506 | RefPtr<RegisterID> tempDst = generator.tempDestination(dst); |
2507 | generator.emitNode(tempDst.get(), m_right); |
2508 | generator.move(local, tempDst.get()); |
2509 | generator.emitProfileType(local, var, divotStart(), divotEnd()); |
2510 | result = generator.move(dst, tempDst.get()); |
2511 | } else { |
2512 | RegisterID* right = generator.emitNode(local, m_right); |
2513 | generator.emitProfileType(right, var, divotStart(), divotEnd()); |
2514 | result = generator.move(dst, right); |
2515 | } |
2516 | |
2517 | if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement) |
2518 | generator.liftTDZCheckIfPossible(var); |
2519 | return result; |
2520 | } |
2521 | |
2522 | if (generator.isStrictMode()) |
2523 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2524 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
2525 | if (m_assignmentContext == AssignmentContext::AssignmentExpression) |
2526 | generator.emitTDZCheckIfNecessary(var, nullptr, scope.get()); |
2527 | if (dst == generator.ignoredResult()) |
2528 | dst = 0; |
2529 | RefPtr<RegisterID> result = generator.emitNode(dst, m_right); |
2530 | if (isReadOnly) { |
2531 | RegisterID* result = generator.emitNode(dst, m_right); // Execute side effects first. |
2532 | bool threwException = generator.emitReadOnlyExceptionIfNeeded(var); |
2533 | if (threwException) |
2534 | return result; |
2535 | } |
2536 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2537 | RegisterID* returnResult = result.get(); |
2538 | if (!isReadOnly) { |
2539 | returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, initializationModeForAssignmentContext(m_assignmentContext)); |
2540 | generator.emitProfileType(result.get(), var, divotStart(), divotEnd()); |
2541 | } |
2542 | |
2543 | if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement) |
2544 | generator.liftTDZCheckIfPossible(var); |
2545 | return returnResult; |
2546 | } |
2547 | |
2548 | // ------------------------------ AssignDotNode ----------------------------------- |
2549 | |
2550 | RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2551 | { |
2552 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); |
2553 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); |
2554 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
2555 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2556 | RefPtr<RegisterID> forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.move(generator.tempDestination(result.get()), result.get()); |
2557 | if (m_base->isSuperNode()) { |
2558 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
2559 | generator.emitPutById(base.get(), thisValue.get(), m_ident, forwardResult.get()); |
2560 | } else |
2561 | generator.emitPutById(base.get(), m_ident, forwardResult.get()); |
2562 | generator.emitProfileType(forwardResult.get(), divotStart(), divotEnd()); |
2563 | return generator.move(dst, forwardResult.get()); |
2564 | } |
2565 | |
2566 | // ------------------------------ ReadModifyDotNode ----------------------------------- |
2567 | |
2568 | RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2569 | { |
2570 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); |
2571 | |
2572 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
2573 | RefPtr<RegisterID> value; |
2574 | RefPtr<RegisterID> thisValue; |
2575 | if (m_base->isSuperNode()) { |
2576 | thisValue = generator.ensureThis(); |
2577 | value = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), m_ident); |
2578 | } else |
2579 | value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); |
2580 | 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())); |
2581 | |
2582 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2583 | RegisterID* ret; |
2584 | if (m_base->isSuperNode()) |
2585 | ret = generator.emitPutById(base.get(), thisValue.get(), m_ident, updatedValue); |
2586 | else |
2587 | ret = generator.emitPutById(base.get(), m_ident, updatedValue); |
2588 | generator.emitProfileType(updatedValue, divotStart(), divotEnd()); |
2589 | return ret; |
2590 | } |
2591 | |
2592 | // ------------------------------ AssignErrorNode ----------------------------------- |
2593 | |
2594 | RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
2595 | { |
2596 | return emitThrowReferenceError(generator, "Left side of assignment is not a reference."_s ); |
2597 | } |
2598 | |
2599 | // ------------------------------ AssignBracketNode ----------------------------------- |
2600 | |
2601 | RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2602 | { |
2603 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); |
2604 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSideForProperty(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); |
2605 | RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); |
2606 | RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right); |
2607 | |
2608 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2609 | RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.move(generator.tempDestination(result.get()), result.get()); |
2610 | |
2611 | if (isNonIndexStringElement(*m_subscript)) { |
2612 | if (m_base->isSuperNode()) { |
2613 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
2614 | generator.emitPutById(base.get(), thisValue.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult); |
2615 | } else |
2616 | generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult); |
2617 | } else { |
2618 | if (m_base->isSuperNode()) { |
2619 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
2620 | generator.emitPutByVal(base.get(), thisValue.get(), property.get(), forwardResult); |
2621 | } else |
2622 | generator.emitPutByVal(base.get(), property.get(), forwardResult); |
2623 | } |
2624 | |
2625 | generator.emitProfileType(forwardResult, divotStart(), divotEnd()); |
2626 | return generator.move(dst, forwardResult); |
2627 | } |
2628 | |
2629 | // ------------------------------ ReadModifyBracketNode ----------------------------------- |
2630 | |
2631 | RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2632 | { |
2633 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); |
2634 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSideForProperty(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); |
2635 | |
2636 | generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); |
2637 | RefPtr<RegisterID> value; |
2638 | RefPtr<RegisterID> thisValue; |
2639 | if (m_base->isSuperNode()) { |
2640 | thisValue = generator.ensureThis(); |
2641 | value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisValue.get(), property.get()); |
2642 | } else |
2643 | value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); |
2644 | 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())); |
2645 | |
2646 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2647 | if (m_base->isSuperNode()) |
2648 | generator.emitPutByVal(base.get(), thisValue.get(), property.get(), updatedValue); |
2649 | else |
2650 | generator.emitPutByVal(base.get(), property.get(), updatedValue); |
2651 | generator.emitProfileType(updatedValue, divotStart(), divotEnd()); |
2652 | |
2653 | return updatedValue; |
2654 | } |
2655 | |
2656 | // ------------------------------ CommaNode ------------------------------------ |
2657 | |
2658 | RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2659 | { |
2660 | CommaNode* node = this; |
2661 | for (; node && node->next(); node = node->next()) |
2662 | generator.emitNode(generator.ignoredResult(), node->m_expr); |
2663 | return generator.emitNodeInTailPosition(dst, node->m_expr); |
2664 | } |
2665 | |
2666 | // ------------------------------ SourceElements ------------------------------- |
2667 | |
2668 | inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2669 | { |
2670 | StatementNode* lastStatementWithCompletionValue = nullptr; |
2671 | if (generator.shouldBeConcernedWithCompletionValue()) { |
2672 | for (StatementNode* statement = m_head; statement; statement = statement->next()) { |
2673 | if (statement->hasCompletionValue()) |
2674 | lastStatementWithCompletionValue = statement; |
2675 | } |
2676 | } |
2677 | |
2678 | for (StatementNode* statement = m_head; statement; statement = statement->next()) { |
2679 | if (statement == lastStatementWithCompletionValue) |
2680 | generator.emitLoad(dst, jsUndefined()); |
2681 | generator.emitNodeInTailPosition(dst, statement); |
2682 | } |
2683 | } |
2684 | |
2685 | // ------------------------------ BlockNode ------------------------------------ |
2686 | |
2687 | void BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2688 | { |
2689 | if (!m_statements) |
2690 | return; |
2691 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested); |
2692 | m_statements->emitBytecode(generator, dst); |
2693 | generator.popLexicalScope(this); |
2694 | } |
2695 | |
2696 | // ------------------------------ EmptyStatementNode --------------------------- |
2697 | |
2698 | void EmptyStatementNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
2699 | { |
2700 | RELEASE_ASSERT(needsDebugHook()); |
2701 | } |
2702 | |
2703 | // ------------------------------ DebuggerStatementNode --------------------------- |
2704 | |
2705 | void DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
2706 | { |
2707 | generator.emitDebugHook(DidReachBreakpoint, position()); |
2708 | } |
2709 | |
2710 | // ------------------------------ ExprStatementNode ---------------------------- |
2711 | |
2712 | void ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2713 | { |
2714 | ASSERT(m_expr); |
2715 | generator.emitNode(dst, m_expr); |
2716 | } |
2717 | |
2718 | // ------------------------------ DeclarationStatement ---------------------------- |
2719 | |
2720 | void DeclarationStatement::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
2721 | { |
2722 | ASSERT(m_expr); |
2723 | generator.emitNode(m_expr); |
2724 | } |
2725 | |
2726 | // ------------------------------ EmptyVarExpression ---------------------------- |
2727 | |
2728 | RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
2729 | { |
2730 | // It's safe to return null here because this node will always be a child node of DeclarationStatement which ignores our return value. |
2731 | if (!generator.shouldEmitTypeProfilerHooks()) |
2732 | return nullptr; |
2733 | |
2734 | Variable var = generator.variable(m_ident); |
2735 | if (RegisterID* local = var.local()) |
2736 | generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); |
2737 | else { |
2738 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
2739 | RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); |
2740 | generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); |
2741 | } |
2742 | |
2743 | return nullptr; |
2744 | } |
2745 | |
2746 | // ------------------------------ EmptyLetExpression ---------------------------- |
2747 | |
2748 | RegisterID* EmptyLetExpression::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
2749 | { |
2750 | // Lexical declarations like 'let' must move undefined into their variables so we don't |
2751 | // get TDZ errors for situations like this: `let x; x;` |
2752 | Variable var = generator.variable(m_ident); |
2753 | if (RegisterID* local = var.local()) { |
2754 | generator.emitLoad(local, jsUndefined()); |
2755 | generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); |
2756 | } else { |
2757 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
2758 | RefPtr<RegisterID> value = generator.emitLoad(nullptr, jsUndefined()); |
2759 | generator.emitPutToScope(scope.get(), var, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::Initialization); |
2760 | generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); |
2761 | } |
2762 | |
2763 | generator.liftTDZCheckIfPossible(var); |
2764 | |
2765 | // It's safe to return null here because this node will always be a child node of DeclarationStatement which ignores our return value. |
2766 | return nullptr; |
2767 | } |
2768 | |
2769 | // ------------------------------ IfElseNode --------------------------------------- |
2770 | |
2771 | static inline StatementNode* singleStatement(StatementNode* statementNode) |
2772 | { |
2773 | if (statementNode->isBlock()) |
2774 | return static_cast<BlockNode*>(statementNode)->singleStatement(); |
2775 | return statementNode; |
2776 | } |
2777 | |
2778 | bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock, |
2779 | Label*& trueTarget, FallThroughMode& fallThroughMode) |
2780 | { |
2781 | StatementNode* singleStatement = JSC::singleStatement(ifBlock); |
2782 | if (!singleStatement) |
2783 | return false; |
2784 | |
2785 | if (singleStatement->isBreak()) { |
2786 | BreakNode* breakNode = static_cast<BreakNode*>(singleStatement); |
2787 | Label* target = breakNode->trivialTarget(generator); |
2788 | if (!target) |
2789 | return false; |
2790 | trueTarget = target; |
2791 | fallThroughMode = FallThroughMeansFalse; |
2792 | return true; |
2793 | } |
2794 | |
2795 | if (singleStatement->isContinue()) { |
2796 | ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement); |
2797 | Label* target = continueNode->trivialTarget(generator); |
2798 | if (!target) |
2799 | return false; |
2800 | trueTarget = target; |
2801 | fallThroughMode = FallThroughMeansFalse; |
2802 | return true; |
2803 | } |
2804 | |
2805 | return false; |
2806 | } |
2807 | |
2808 | void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2809 | { |
2810 | if (generator.shouldBeConcernedWithCompletionValue()) { |
2811 | if (m_ifBlock->hasEarlyBreakOrContinue() || (m_elseBlock && m_elseBlock->hasEarlyBreakOrContinue())) |
2812 | generator.emitLoad(dst, jsUndefined()); |
2813 | } |
2814 | |
2815 | Ref<Label> beforeThen = generator.newLabel(); |
2816 | Ref<Label> beforeElse = generator.newLabel(); |
2817 | Ref<Label> afterElse = generator.newLabel(); |
2818 | |
2819 | Label* trueTarget = beforeThen.ptr(); |
2820 | Label& falseTarget = beforeElse.get(); |
2821 | FallThroughMode fallThroughMode = FallThroughMeansTrue; |
2822 | bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode); |
2823 | |
2824 | generator.emitNodeInConditionContext(m_condition, *trueTarget, falseTarget, fallThroughMode); |
2825 | generator.emitLabel(beforeThen.get()); |
2826 | generator.emitProfileControlFlow(m_ifBlock->startOffset()); |
2827 | |
2828 | if (!didFoldIfBlock) { |
2829 | generator.emitNodeInTailPosition(dst, m_ifBlock); |
2830 | if (m_elseBlock) |
2831 | generator.emitJump(afterElse.get()); |
2832 | } |
2833 | |
2834 | generator.emitLabel(beforeElse.get()); |
2835 | |
2836 | if (m_elseBlock) { |
2837 | generator.emitProfileControlFlow(m_ifBlock->endOffset() + (m_ifBlock->isBlock() ? 1 : 0)); |
2838 | generator.emitNodeInTailPosition(dst, m_elseBlock); |
2839 | } |
2840 | |
2841 | generator.emitLabel(afterElse.get()); |
2842 | StatementNode* endingBlock = m_elseBlock ? m_elseBlock : m_ifBlock; |
2843 | generator.emitProfileControlFlow(endingBlock->endOffset() + (endingBlock->isBlock() ? 1 : 0)); |
2844 | } |
2845 | |
2846 | // ------------------------------ DoWhileNode ---------------------------------- |
2847 | |
2848 | void DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2849 | { |
2850 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
2851 | generator.emitLoad(dst, jsUndefined()); |
2852 | |
2853 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
2854 | |
2855 | Ref<Label> topOfLoop = generator.newLabel(); |
2856 | generator.emitLabel(topOfLoop.get()); |
2857 | generator.emitLoopHint(); |
2858 | |
2859 | generator.emitNodeInTailPosition(dst, m_statement); |
2860 | |
2861 | generator.emitLabel(*scope->continueTarget()); |
2862 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
2863 | |
2864 | generator.emitLabel(scope->breakTarget()); |
2865 | } |
2866 | |
2867 | // ------------------------------ WhileNode ------------------------------------ |
2868 | |
2869 | void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2870 | { |
2871 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
2872 | generator.emitLoad(dst, jsUndefined()); |
2873 | |
2874 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
2875 | Ref<Label> topOfLoop = generator.newLabel(); |
2876 | |
2877 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); |
2878 | |
2879 | generator.emitLabel(topOfLoop.get()); |
2880 | generator.emitLoopHint(); |
2881 | |
2882 | generator.emitProfileControlFlow(m_statement->startOffset()); |
2883 | generator.emitNodeInTailPosition(dst, m_statement); |
2884 | |
2885 | generator.emitLabel(*scope->continueTarget()); |
2886 | |
2887 | generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
2888 | |
2889 | generator.emitLabel(scope->breakTarget()); |
2890 | |
2891 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); |
2892 | } |
2893 | |
2894 | // ------------------------------ ForNode -------------------------------------- |
2895 | |
2896 | void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
2897 | { |
2898 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
2899 | generator.emitLoad(dst, jsUndefined()); |
2900 | |
2901 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
2902 | |
2903 | RegisterID* forLoopSymbolTable = nullptr; |
2904 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable); |
2905 | |
2906 | if (m_expr1) |
2907 | generator.emitNode(generator.ignoredResult(), m_expr1); |
2908 | |
2909 | Ref<Label> topOfLoop = generator.newLabel(); |
2910 | if (m_expr2) |
2911 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); |
2912 | |
2913 | generator.emitLabel(topOfLoop.get()); |
2914 | generator.emitLoopHint(); |
2915 | generator.emitProfileControlFlow(m_statement->startOffset()); |
2916 | |
2917 | generator.emitNodeInTailPosition(dst, m_statement); |
2918 | |
2919 | generator.emitLabel(*scope->continueTarget()); |
2920 | generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable); |
2921 | if (m_expr3) |
2922 | generator.emitNode(generator.ignoredResult(), m_expr3); |
2923 | |
2924 | if (m_expr2) |
2925 | generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); |
2926 | else |
2927 | generator.emitJump(topOfLoop.get()); |
2928 | |
2929 | generator.emitLabel(scope->breakTarget()); |
2930 | generator.popLexicalScope(this); |
2931 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); |
2932 | } |
2933 | |
2934 | // ------------------------------ ForInNode ------------------------------------ |
2935 | |
2936 | RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator) |
2937 | { |
2938 | if (m_lexpr->isResolveNode()) { |
2939 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); |
2940 | return generator.variable(ident).local(); |
2941 | } |
2942 | |
2943 | if (m_lexpr->isDestructuringNode()) { |
2944 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); |
2945 | auto binding = assignNode->bindings(); |
2946 | if (!binding->isBindingNode()) |
2947 | return nullptr; |
2948 | |
2949 | auto simpleBinding = static_cast<BindingNode*>(binding); |
2950 | const Identifier& ident = simpleBinding->boundProperty(); |
2951 | Variable var = generator.variable(ident); |
2952 | if (var.isSpecial()) |
2953 | return nullptr; |
2954 | return var.local(); |
2955 | } |
2956 | |
2957 | return nullptr; |
2958 | } |
2959 | |
2960 | void ForInNode::(BytecodeGenerator& generator, RegisterID* propertyName) |
2961 | { |
2962 | auto lambdaEmitResolveVariable = [&] (const Identifier& ident) { |
2963 | Variable var = generator.variable(ident); |
2964 | if (RegisterID* local = var.local()) { |
2965 | if (var.isReadOnly()) |
2966 | generator.emitReadOnlyExceptionIfNeeded(var); |
2967 | generator.move(local, propertyName); |
2968 | } else { |
2969 | if (generator.isStrictMode()) |
2970 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2971 | if (var.isReadOnly()) |
2972 | generator.emitReadOnlyExceptionIfNeeded(var); |
2973 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
2974 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
2975 | generator.emitPutToScope(scope.get(), var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::NotInitialization); |
2976 | } |
2977 | generator.emitProfileType(propertyName, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); |
2978 | }; |
2979 | |
2980 | if (m_lexpr->isResolveNode()) { |
2981 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); |
2982 | lambdaEmitResolveVariable(ident); |
2983 | return; |
2984 | } |
2985 | |
2986 | if (m_lexpr->isAssignResolveNode()) { |
2987 | const Identifier& ident = static_cast<AssignResolveNode*>(m_lexpr)->identifier(); |
2988 | lambdaEmitResolveVariable(ident); |
2989 | return; |
2990 | } |
2991 | |
2992 | if (m_lexpr->isDotAccessorNode()) { |
2993 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); |
2994 | const Identifier& ident = assignNode->identifier(); |
2995 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
2996 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
2997 | if (assignNode->base()->isSuperNode()) { |
2998 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
2999 | generator.emitPutById(base.get(), thisValue.get(), ident, propertyName); |
3000 | } else |
3001 | generator.emitPutById(base.get(), ident, propertyName); |
3002 | generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd()); |
3003 | return; |
3004 | } |
3005 | if (m_lexpr->isBracketAccessorNode()) { |
3006 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); |
3007 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
3008 | RefPtr<RegisterID> subscript = generator.emitNodeForProperty(assignNode->subscript()); |
3009 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
3010 | if (assignNode->base()->isSuperNode()) { |
3011 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
3012 | generator.emitPutByVal(base.get(), thisValue.get(), subscript.get(), propertyName); |
3013 | } else |
3014 | generator.emitPutByVal(base.get(), subscript.get(), propertyName); |
3015 | generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd()); |
3016 | return; |
3017 | } |
3018 | |
3019 | if (m_lexpr->isDestructuringNode()) { |
3020 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); |
3021 | auto binding = assignNode->bindings(); |
3022 | if (!binding->isBindingNode()) { |
3023 | assignNode->bindings()->bindValue(generator, propertyName); |
3024 | return; |
3025 | } |
3026 | |
3027 | auto simpleBinding = static_cast<BindingNode*>(binding); |
3028 | const Identifier& ident = simpleBinding->boundProperty(); |
3029 | Variable var = generator.variable(ident); |
3030 | if (!var.local() || var.isSpecial()) { |
3031 | assignNode->bindings()->bindValue(generator, propertyName); |
3032 | return; |
3033 | } |
3034 | generator.move(var.local(), propertyName); |
3035 | generator.emitProfileType(propertyName, var, simpleBinding->divotStart(), simpleBinding->divotEnd()); |
3036 | return; |
3037 | } |
3038 | |
3039 | RELEASE_ASSERT_NOT_REACHED(); |
3040 | } |
3041 | |
3042 | void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3043 | { |
3044 | if (!m_lexpr->isAssignResolveNode() && !m_lexpr->isAssignmentLocation()) { |
3045 | emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."_s ); |
3046 | return; |
3047 | } |
3048 | |
3049 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
3050 | generator.emitLoad(dst, jsUndefined()); |
3051 | |
3052 | Ref<Label> end = generator.newLabel(); |
3053 | |
3054 | RegisterID* forLoopSymbolTable = nullptr; |
3055 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable); |
3056 | |
3057 | if (m_lexpr->isAssignResolveNode()) |
3058 | generator.emitNode(generator.ignoredResult(), m_lexpr); |
3059 | |
3060 | RefPtr<RegisterID> base = generator.newTemporary(); |
3061 | RefPtr<RegisterID> length; |
3062 | RefPtr<RegisterID> enumerator; |
3063 | |
3064 | generator.emitNode(base.get(), m_expr); |
3065 | RefPtr<RegisterID> local = this->tryGetBoundLocal(generator); |
3066 | RefPtr<RegisterID> enumeratorIndex; |
3067 | |
3068 | // Pause at the assignment expression for each for..in iteration. |
3069 | generator.emitDebugHook(m_lexpr); |
3070 | |
3071 | int profilerStartOffset = m_statement->startOffset(); |
3072 | int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0); |
3073 | |
3074 | enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get()); |
3075 | |
3076 | BytecodeGenerator::PreservedTDZStack preservedTDZStack; |
3077 | generator.preserveTDZStack(preservedTDZStack); |
3078 | |
3079 | // Indexed property loop. |
3080 | { |
3081 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
3082 | Ref<Label> loopStart = generator.newLabel(); |
3083 | Ref<Label> loopEnd = generator.newLabel(); |
3084 | |
3085 | length = generator.emitGetEnumerableLength(generator.newTemporary(), enumerator.get()); |
3086 | RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0)); |
3087 | RefPtr<RegisterID> propertyName = generator.newTemporary(); |
3088 | |
3089 | generator.emitLabel(loopStart.get()); |
3090 | generator.emitLoopHint(); |
3091 | |
3092 | RefPtr<RegisterID> result = generator.emitEqualityOp<OpLess>(generator.newTemporary(), i.get(), length.get()); |
3093 | generator.emitJumpIfFalse(result.get(), loopEnd.get()); |
3094 | generator.emitHasIndexedProperty(result.get(), base.get(), i.get()); |
3095 | generator.emitJumpIfFalse(result.get(), *scope->continueTarget()); |
3096 | |
3097 | generator.emitToIndexString(propertyName.get(), i.get()); |
3098 | this->emitLoopHeader(generator, propertyName.get()); |
3099 | |
3100 | generator.emitProfileControlFlow(profilerStartOffset); |
3101 | |
3102 | generator.pushIndexedForInScope(local.get(), i.get()); |
3103 | generator.emitNode(dst, m_statement); |
3104 | generator.popIndexedForInScope(local.get()); |
3105 | |
3106 | generator.emitProfileControlFlow(profilerEndOffset); |
3107 | |
3108 | generator.emitLabel(*scope->continueTarget()); |
3109 | generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable); |
3110 | generator.emitInc(i.get()); |
3111 | generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration. |
3112 | generator.emitJump(loopStart.get()); |
3113 | |
3114 | generator.emitLabel(scope->breakTarget()); |
3115 | generator.emitJump(end.get()); |
3116 | generator.emitLabel(loopEnd.get()); |
3117 | } |
3118 | generator.restoreTDZStack(preservedTDZStack); |
3119 | |
3120 | // Structure property loop. |
3121 | { |
3122 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
3123 | Ref<Label> loopStart = generator.newLabel(); |
3124 | Ref<Label> loopEnd = generator.newLabel(); |
3125 | |
3126 | enumeratorIndex = generator.emitLoad(generator.newTemporary(), jsNumber(0)); |
3127 | RefPtr<RegisterID> propertyName = generator.newTemporary(); |
3128 | generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); |
3129 | |
3130 | generator.emitLabel(loopStart.get()); |
3131 | generator.emitLoopHint(); |
3132 | |
3133 | RefPtr<RegisterID> result = generator.emitUnaryOp<OpEqNull>(generator.newTemporary(), propertyName.get()); |
3134 | generator.emitJumpIfTrue(result.get(), loopEnd.get()); |
3135 | generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), enumerator.get()); |
3136 | generator.emitJumpIfFalse(result.get(), *scope->continueTarget()); |
3137 | |
3138 | this->emitLoopHeader(generator, propertyName.get()); |
3139 | |
3140 | generator.emitProfileControlFlow(profilerStartOffset); |
3141 | |
3142 | generator.pushStructureForInScope(local.get(), enumeratorIndex.get(), propertyName.get(), enumerator.get()); |
3143 | generator.emitNode(dst, m_statement); |
3144 | generator.popStructureForInScope(local.get()); |
3145 | |
3146 | generator.emitProfileControlFlow(profilerEndOffset); |
3147 | |
3148 | generator.emitLabel(*scope->continueTarget()); |
3149 | generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable); |
3150 | generator.emitInc(enumeratorIndex.get()); |
3151 | generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); |
3152 | generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration. |
3153 | generator.emitJump(loopStart.get()); |
3154 | |
3155 | generator.emitLabel(scope->breakTarget()); |
3156 | generator.emitJump(end.get()); |
3157 | generator.emitLabel(loopEnd.get()); |
3158 | } |
3159 | generator.restoreTDZStack(preservedTDZStack); |
3160 | |
3161 | // Generic property loop. |
3162 | { |
3163 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); |
3164 | Ref<Label> loopStart = generator.newLabel(); |
3165 | Ref<Label> loopEnd = generator.newLabel(); |
3166 | |
3167 | RefPtr<RegisterID> propertyName = generator.newTemporary(); |
3168 | |
3169 | generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); |
3170 | |
3171 | generator.emitLabel(loopStart.get()); |
3172 | generator.emitLoopHint(); |
3173 | |
3174 | RefPtr<RegisterID> result = generator.emitUnaryOp<OpEqNull>(generator.newTemporary(), propertyName.get()); |
3175 | generator.emitJumpIfTrue(result.get(), loopEnd.get()); |
3176 | |
3177 | generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get()); |
3178 | generator.emitJumpIfFalse(result.get(), *scope->continueTarget()); |
3179 | |
3180 | this->emitLoopHeader(generator, propertyName.get()); |
3181 | |
3182 | generator.emitProfileControlFlow(profilerStartOffset); |
3183 | |
3184 | generator.emitNode(dst, m_statement); |
3185 | |
3186 | generator.emitLabel(*scope->continueTarget()); |
3187 | generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable); |
3188 | generator.emitInc(enumeratorIndex.get()); |
3189 | generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); |
3190 | generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration. |
3191 | generator.emitJump(loopStart.get()); |
3192 | |
3193 | generator.emitLabel(scope->breakTarget()); |
3194 | generator.emitJump(end.get()); |
3195 | generator.emitLabel(loopEnd.get()); |
3196 | } |
3197 | |
3198 | generator.emitLabel(end.get()); |
3199 | generator.popLexicalScope(this); |
3200 | generator.emitProfileControlFlow(profilerEndOffset); |
3201 | } |
3202 | |
3203 | // ------------------------------ ForOfNode ------------------------------------ |
3204 | void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3205 | { |
3206 | if (!m_lexpr->isAssignmentLocation()) { |
3207 | emitThrowReferenceError(generator, "Left side of for-of statement is not a reference."_s ); |
3208 | return; |
3209 | } |
3210 | |
3211 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
3212 | generator.emitLoad(dst, jsUndefined()); |
3213 | |
3214 | RegisterID* forLoopSymbolTable = nullptr; |
3215 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable); |
3216 | auto = scopedLambda<void(BytecodeGenerator&, RegisterID*)>([this, dst](BytecodeGenerator& generator, RegisterID* value) |
3217 | { |
3218 | if (m_lexpr->isResolveNode()) { |
3219 | const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); |
3220 | Variable var = generator.variable(ident); |
3221 | if (RegisterID* local = var.local()) { |
3222 | if (var.isReadOnly()) |
3223 | generator.emitReadOnlyExceptionIfNeeded(var); |
3224 | generator.move(local, value); |
3225 | } else { |
3226 | if (generator.isStrictMode()) |
3227 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
3228 | if (var.isReadOnly()) |
3229 | generator.emitReadOnlyExceptionIfNeeded(var); |
3230 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
3231 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
3232 | generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::NotInitialization); |
3233 | } |
3234 | generator.emitProfileType(value, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); |
3235 | } else if (m_lexpr->isDotAccessorNode()) { |
3236 | DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); |
3237 | const Identifier& ident = assignNode->identifier(); |
3238 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
3239 | |
3240 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
3241 | if (assignNode->base()->isSuperNode()) { |
3242 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
3243 | generator.emitPutById(base.get(), thisValue.get(), ident, value); |
3244 | } else |
3245 | generator.emitPutById(base.get(), ident, value); |
3246 | generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd()); |
3247 | } else if (m_lexpr->isBracketAccessorNode()) { |
3248 | BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); |
3249 | RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); |
3250 | RegisterID* subscript = generator.emitNodeForProperty(assignNode->subscript()); |
3251 | |
3252 | generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); |
3253 | if (assignNode->base()->isSuperNode()) { |
3254 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
3255 | generator.emitPutByVal(base.get(), thisValue.get(), subscript, value); |
3256 | } else |
3257 | generator.emitPutByVal(base.get(), subscript, value); |
3258 | generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd()); |
3259 | } else { |
3260 | ASSERT(m_lexpr->isDestructuringNode()); |
3261 | DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); |
3262 | assignNode->bindings()->bindValue(generator, value); |
3263 | } |
3264 | generator.emitProfileControlFlow(m_statement->startOffset()); |
3265 | generator.emitNode(dst, m_statement); |
3266 | }); |
3267 | generator.emitEnumeration(this, m_expr, extractor, this, forLoopSymbolTable); |
3268 | generator.popLexicalScope(this); |
3269 | generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); |
3270 | } |
3271 | |
3272 | // ------------------------------ ContinueNode --------------------------------- |
3273 | |
3274 | Label* ContinueNode::trivialTarget(BytecodeGenerator& generator) |
3275 | { |
3276 | if (generator.shouldEmitDebugHooks()) |
3277 | return nullptr; |
3278 | |
3279 | LabelScope* scope = generator.continueTarget(m_ident); |
3280 | ASSERT(scope); |
3281 | |
3282 | if (generator.labelScopeDepth() != scope->scopeDepth()) |
3283 | return nullptr; |
3284 | |
3285 | return scope->continueTarget(); |
3286 | } |
3287 | |
3288 | void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3289 | { |
3290 | LabelScope* scope = generator.continueTarget(m_ident); |
3291 | ASSERT(scope); |
3292 | |
3293 | bool hasFinally = generator.emitJumpViaFinallyIfNeeded(scope->scopeDepth(), *scope->continueTarget()); |
3294 | if (!hasFinally) { |
3295 | int lexicalScopeIndex = generator.labelScopeDepthToLexicalScopeIndex(scope->scopeDepth()); |
3296 | generator.restoreScopeRegister(lexicalScopeIndex); |
3297 | generator.emitJump(*scope->continueTarget()); |
3298 | } |
3299 | |
3300 | generator.emitProfileControlFlow(endOffset()); |
3301 | } |
3302 | |
3303 | // ------------------------------ BreakNode ------------------------------------ |
3304 | |
3305 | Label* BreakNode::trivialTarget(BytecodeGenerator& generator) |
3306 | { |
3307 | if (generator.shouldEmitDebugHooks()) |
3308 | return nullptr; |
3309 | |
3310 | LabelScope* scope = generator.breakTarget(m_ident); |
3311 | ASSERT(scope); |
3312 | |
3313 | if (generator.labelScopeDepth() != scope->scopeDepth()) |
3314 | return nullptr; |
3315 | |
3316 | return &scope->breakTarget(); |
3317 | } |
3318 | |
3319 | void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3320 | { |
3321 | LabelScope* scope = generator.breakTarget(m_ident); |
3322 | ASSERT(scope); |
3323 | |
3324 | bool hasFinally = generator.emitJumpViaFinallyIfNeeded(scope->scopeDepth(), scope->breakTarget()); |
3325 | if (!hasFinally) { |
3326 | int lexicalScopeIndex = generator.labelScopeDepthToLexicalScopeIndex(scope->scopeDepth()); |
3327 | generator.restoreScopeRegister(lexicalScopeIndex); |
3328 | generator.emitJump(scope->breakTarget()); |
3329 | } |
3330 | |
3331 | generator.emitProfileControlFlow(endOffset()); |
3332 | } |
3333 | |
3334 | // ------------------------------ ReturnNode ----------------------------------- |
3335 | |
3336 | void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3337 | { |
3338 | ASSERT(generator.codeType() == FunctionCode); |
3339 | |
3340 | if (dst == generator.ignoredResult()) |
3341 | dst = 0; |
3342 | |
3343 | RefPtr<RegisterID> returnRegister = m_value ? generator.emitNodeInTailPosition(dst, m_value) : generator.emitLoad(dst, jsUndefined()); |
3344 | |
3345 | generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, divotStart(), divotEnd()); |
3346 | |
3347 | bool hasFinally = generator.emitReturnViaFinallyIfNeeded(returnRegister.get()); |
3348 | if (!hasFinally) { |
3349 | if (generator.parseMode() == SourceParseMode::AsyncGeneratorBodyMode) { |
3350 | returnRegister = generator.move(generator.newTemporary(), returnRegister.get()); |
3351 | generator.emitAwait(returnRegister.get()); |
3352 | } |
3353 | |
3354 | generator.emitWillLeaveCallFrameDebugHook(); |
3355 | generator.emitReturn(returnRegister.get()); |
3356 | } |
3357 | |
3358 | generator.emitProfileControlFlow(endOffset()); |
3359 | // Emitting an unreachable return here is needed in case this op_profile_control_flow is the |
3360 | // last opcode in a CodeBlock because a CodeBlock's instructions must end with a terminal opcode. |
3361 | if (generator.shouldEmitControlFlowProfilerHooks()) |
3362 | generator.emitReturn(generator.emitLoad(nullptr, jsUndefined())); |
3363 | } |
3364 | |
3365 | // ------------------------------ WithNode ------------------------------------- |
3366 | |
3367 | void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3368 | { |
3369 | RefPtr<RegisterID> scope = generator.emitNode(m_expr); |
3370 | generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot); |
3371 | generator.emitPushWithScope(scope.get()); |
3372 | if (generator.shouldBeConcernedWithCompletionValue() && m_statement->hasEarlyBreakOrContinue()) |
3373 | generator.emitLoad(dst, jsUndefined()); |
3374 | generator.emitNodeInTailPosition(dst, m_statement); |
3375 | generator.emitPopWithScope(); |
3376 | } |
3377 | |
3378 | // ------------------------------ CaseClauseNode -------------------------------- |
3379 | |
3380 | inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3381 | { |
3382 | generator.emitProfileControlFlow(m_startOffset); |
3383 | if (!m_statements) |
3384 | return; |
3385 | m_statements->emitBytecode(generator, dst); |
3386 | } |
3387 | |
3388 | // ------------------------------ CaseBlockNode -------------------------------- |
3389 | |
3390 | enum SwitchKind { |
3391 | SwitchUnset = 0, |
3392 | SwitchNumber = 1, |
3393 | SwitchString = 2, |
3394 | SwitchNeither = 3 |
3395 | }; |
3396 | |
3397 | static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) |
3398 | { |
3399 | for (; list; list = list->getNext()) { |
3400 | ExpressionNode* clauseExpression = list->getClause()->expr(); |
3401 | literalVector.append(clauseExpression); |
3402 | if (clauseExpression->isNumber()) { |
3403 | double value = static_cast<NumberNode*>(clauseExpression)->value(); |
3404 | int32_t intVal = static_cast<int32_t>(value); |
3405 | if ((typeForTable & ~SwitchNumber) || (intVal != value)) { |
3406 | typeForTable = SwitchNeither; |
3407 | break; |
3408 | } |
3409 | if (intVal < min_num) |
3410 | min_num = intVal; |
3411 | if (intVal > max_num) |
3412 | max_num = intVal; |
3413 | typeForTable = SwitchNumber; |
3414 | continue; |
3415 | } |
3416 | if (clauseExpression->isString()) { |
3417 | if (typeForTable & ~SwitchString) { |
3418 | typeForTable = SwitchNeither; |
3419 | break; |
3420 | } |
3421 | const String& value = static_cast<StringNode*>(clauseExpression)->value().string(); |
3422 | if (singleCharacterSwitch &= value.length() == 1) { |
3423 | int32_t intVal = value[0]; |
3424 | if (intVal < min_num) |
3425 | min_num = intVal; |
3426 | if (intVal > max_num) |
3427 | max_num = intVal; |
3428 | } |
3429 | typeForTable = SwitchString; |
3430 | continue; |
3431 | } |
3432 | typeForTable = SwitchNeither; |
3433 | break; |
3434 | } |
3435 | } |
3436 | |
3437 | static inline size_t length(ClauseListNode* list1, ClauseListNode* list2) |
3438 | { |
3439 | size_t length = 0; |
3440 | for (ClauseListNode* node = list1; node; node = node->getNext()) |
3441 | ++length; |
3442 | for (ClauseListNode* node = list2; node; node = node->getNext()) |
3443 | ++length; |
3444 | return length; |
3445 | } |
3446 | |
3447 | SwitchInfo::SwitchType CaseBlockNode::tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) |
3448 | { |
3449 | if (length(m_list1, m_list2) < s_tableSwitchMinimum) |
3450 | return SwitchInfo::SwitchNone; |
3451 | |
3452 | SwitchKind typeForTable = SwitchUnset; |
3453 | bool singleCharacterSwitch = true; |
3454 | |
3455 | processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); |
3456 | processClauseList(m_list2, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); |
3457 | |
3458 | if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) |
3459 | return SwitchInfo::SwitchNone; |
3460 | |
3461 | if (typeForTable == SwitchNumber) { |
3462 | int32_t range = max_num - min_num; |
3463 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) |
3464 | return SwitchInfo::SwitchImmediate; |
3465 | return SwitchInfo::SwitchNone; |
3466 | } |
3467 | |
3468 | ASSERT(typeForTable == SwitchString); |
3469 | |
3470 | if (singleCharacterSwitch) { |
3471 | int32_t range = max_num - min_num; |
3472 | if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) |
3473 | return SwitchInfo::SwitchCharacter; |
3474 | } |
3475 | |
3476 | return SwitchInfo::SwitchString; |
3477 | } |
3478 | |
3479 | void CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) |
3480 | { |
3481 | Vector<Ref<Label>, 8> labelVector; |
3482 | Vector<ExpressionNode*, 8> literalVector; |
3483 | int32_t min_num = std::numeric_limits<int32_t>::max(); |
3484 | int32_t max_num = std::numeric_limits<int32_t>::min(); |
3485 | SwitchInfo::SwitchType switchType = tryTableSwitch(literalVector, min_num, max_num); |
3486 | |
3487 | Ref<Label> defaultLabel = generator.newLabel(); |
3488 | if (switchType != SwitchInfo::SwitchNone) { |
3489 | // Prepare the various labels |
3490 | for (uint32_t i = 0; i < literalVector.size(); i++) |
3491 | labelVector.append(generator.newLabel()); |
3492 | generator.beginSwitch(switchExpression, switchType); |
3493 | } else { |
3494 | // Setup jumps |
3495 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { |
3496 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); |
3497 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); |
3498 | generator.emitBinaryOp<OpStricteq>(clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); |
3499 | labelVector.append(generator.newLabel()); |
3500 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); |
3501 | } |
3502 | |
3503 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { |
3504 | RefPtr<RegisterID> clauseVal = generator.newTemporary(); |
3505 | generator.emitNode(clauseVal.get(), list->getClause()->expr()); |
3506 | generator.emitBinaryOp<OpStricteq>(clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); |
3507 | labelVector.append(generator.newLabel()); |
3508 | generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); |
3509 | } |
3510 | generator.emitJump(defaultLabel.get()); |
3511 | } |
3512 | |
3513 | size_t i = 0; |
3514 | for (ClauseListNode* list = m_list1; list; list = list->getNext()) { |
3515 | generator.emitLabel(labelVector[i++].get()); |
3516 | list->getClause()->emitBytecode(generator, dst); |
3517 | } |
3518 | |
3519 | if (m_defaultClause) { |
3520 | generator.emitLabel(defaultLabel.get()); |
3521 | m_defaultClause->emitBytecode(generator, dst); |
3522 | } |
3523 | |
3524 | for (ClauseListNode* list = m_list2; list; list = list->getNext()) { |
3525 | generator.emitLabel(labelVector[i++].get()); |
3526 | list->getClause()->emitBytecode(generator, dst); |
3527 | } |
3528 | if (!m_defaultClause) |
3529 | generator.emitLabel(defaultLabel.get()); |
3530 | |
3531 | ASSERT(i == labelVector.size()); |
3532 | if (switchType != SwitchInfo::SwitchNone) { |
3533 | ASSERT(labelVector.size() == literalVector.size()); |
3534 | generator.endSwitch(labelVector.size(), labelVector, literalVector.data(), defaultLabel.get(), min_num, max_num); |
3535 | } |
3536 | } |
3537 | |
3538 | // ------------------------------ SwitchNode ----------------------------------- |
3539 | |
3540 | void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3541 | { |
3542 | if (generator.shouldBeConcernedWithCompletionValue()) |
3543 | generator.emitLoad(dst, jsUndefined()); |
3544 | |
3545 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); |
3546 | |
3547 | RefPtr<RegisterID> r0 = generator.emitNode(m_expr); |
3548 | |
3549 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::DoNotOptimize, BytecodeGenerator::NestedScopeType::IsNested); |
3550 | m_block->emitBytecodeForBlock(generator, r0.get(), dst); |
3551 | generator.popLexicalScope(this); |
3552 | |
3553 | generator.emitLabel(scope->breakTarget()); |
3554 | generator.emitProfileControlFlow(endOffset()); |
3555 | } |
3556 | |
3557 | // ------------------------------ LabelNode ------------------------------------ |
3558 | |
3559 | void LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3560 | { |
3561 | ASSERT(!generator.breakTarget(m_name)); |
3562 | |
3563 | Ref<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); |
3564 | generator.emitNodeInTailPosition(dst, m_statement); |
3565 | |
3566 | generator.emitLabel(scope->breakTarget()); |
3567 | } |
3568 | |
3569 | // ------------------------------ ThrowNode ------------------------------------ |
3570 | |
3571 | void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3572 | { |
3573 | if (dst == generator.ignoredResult()) |
3574 | dst = 0; |
3575 | RefPtr<RegisterID> expr = generator.emitNode(m_expr); |
3576 | generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); |
3577 | generator.emitThrow(expr.get()); |
3578 | |
3579 | generator.emitProfileControlFlow(endOffset()); |
3580 | } |
3581 | |
3582 | // ------------------------------ TryNode -------------------------------------- |
3583 | |
3584 | void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3585 | { |
3586 | // NOTE: The catch and finally blocks must be labeled explicitly, so the |
3587 | // optimizer knows they may be jumped to from anywhere. |
3588 | |
3589 | if (generator.shouldBeConcernedWithCompletionValue() && m_tryBlock->hasEarlyBreakOrContinue()) |
3590 | generator.emitLoad(dst, jsUndefined()); |
3591 | |
3592 | ASSERT(m_catchBlock || m_finallyBlock); |
3593 | |
3594 | RefPtr<Label> catchLabel; |
3595 | RefPtr<Label> catchEndLabel; |
3596 | RefPtr<Label> finallyLabel; |
3597 | RefPtr<Label> finallyEndLabel; |
3598 | Optional<FinallyContext> finallyContext; |
3599 | |
3600 | if (m_finallyBlock) { |
3601 | finallyLabel = generator.newLabel(); |
3602 | finallyEndLabel = generator.newLabel(); |
3603 | |
3604 | finallyContext.emplace(generator, *finallyLabel); |
3605 | generator.pushFinallyControlFlowScope(finallyContext.value()); |
3606 | } |
3607 | if (m_catchBlock) { |
3608 | catchLabel = generator.newLabel(); |
3609 | catchEndLabel = generator.newLabel(); |
3610 | } |
3611 | |
3612 | Ref<Label> tryLabel = generator.newEmittedLabel(); |
3613 | Label& tryHandlerLabel = m_catchBlock ? *catchLabel : *finallyLabel; |
3614 | HandlerType tryHandlerType = m_catchBlock ? HandlerType::Catch : HandlerType::Finally; |
3615 | TryData* tryData = generator.pushTry(tryLabel.get(), tryHandlerLabel, tryHandlerType); |
3616 | TryData* finallyTryData = nullptr; |
3617 | if (!m_catchBlock && m_finallyBlock) |
3618 | finallyTryData = tryData; |
3619 | |
3620 | generator.emitNode(dst, m_tryBlock); |
3621 | |
3622 | if (m_finallyBlock) |
3623 | generator.emitJump(*finallyLabel); |
3624 | else |
3625 | generator.emitJump(*catchEndLabel); |
3626 | |
3627 | Ref<Label> tryEndLabel = generator.newEmittedLabel(); |
3628 | generator.popTry(tryData, tryEndLabel.get()); |
3629 | |
3630 | if (m_catchBlock) { |
3631 | // Uncaught exception path: the catch block. |
3632 | generator.emitLabel(*catchLabel); |
3633 | RefPtr<RegisterID> thrownValueRegister = generator.newTemporary(); |
3634 | RegisterID* completionTypeRegister = m_finallyBlock ? finallyContext->completionTypeRegister() : nullptr; |
3635 | generator.emitOutOfLineCatchHandler(thrownValueRegister.get(), completionTypeRegister, tryData); |
3636 | generator.restoreScopeRegister(); |
3637 | |
3638 | if (m_finallyBlock) { |
3639 | // If the catch block throws an exception and we have a finally block, then the finally |
3640 | // block should "catch" that exception. |
3641 | finallyTryData = generator.pushTry(*catchLabel, *finallyLabel, HandlerType::Finally); |
3642 | } |
3643 | |
3644 | if (m_catchPattern) { |
3645 | generator.emitPushCatchScope(m_lexicalVariables); |
3646 | m_catchPattern->bindValue(generator, thrownValueRegister.get()); |
3647 | } |
3648 | |
3649 | generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1); |
3650 | if (m_finallyBlock) |
3651 | generator.emitNode(dst, m_catchBlock); |
3652 | else |
3653 | generator.emitNodeInTailPosition(dst, m_catchBlock); |
3654 | generator.emitLoad(thrownValueRegister.get(), jsUndefined()); |
3655 | |
3656 | if (m_catchPattern) |
3657 | generator.emitPopCatchScope(m_lexicalVariables); |
3658 | |
3659 | if (m_finallyBlock) { |
3660 | generator.emitLoad(finallyContext->completionTypeRegister(), CompletionType::Normal); |
3661 | generator.emitJump(*finallyLabel); |
3662 | generator.popTry(finallyTryData, *finallyLabel); |
3663 | } |
3664 | |
3665 | generator.emitLabel(*catchEndLabel); |
3666 | generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1); |
3667 | } |
3668 | |
3669 | if (m_finallyBlock) { |
3670 | generator.popFinallyControlFlowScope(); |
3671 | |
3672 | // Entry to the finally block for CompletionType::Throw to be generated later. |
3673 | generator.emitOutOfLineFinallyHandler(finallyContext->completionValueRegister(), finallyContext->completionTypeRegister(), finallyTryData); |
3674 | |
3675 | // Entry to the finally block for CompletionTypes other than Throw. |
3676 | generator.emitLabel(*finallyLabel); |
3677 | generator.restoreScopeRegister(); |
3678 | |
3679 | int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1; |
3680 | generator.emitProfileControlFlow(finallyStartOffset); |
3681 | generator.emitNodeInTailPosition(m_finallyBlock); |
3682 | |
3683 | generator.emitFinallyCompletion(finallyContext.value(), *finallyEndLabel); |
3684 | generator.emitLabel(*finallyEndLabel); |
3685 | generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1); |
3686 | } |
3687 | } |
3688 | |
3689 | // ------------------------------ ScopeNode ----------------------------- |
3690 | |
3691 | inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3692 | { |
3693 | if (!m_statements) |
3694 | return; |
3695 | m_statements->emitBytecode(generator, dst); |
3696 | } |
3697 | |
3698 | static void emitProgramNodeBytecode(BytecodeGenerator& generator, ScopeNode& scopeNode) |
3699 | { |
3700 | generator.emitDebugHook(WillExecuteProgram, scopeNode.startLine(), scopeNode.startStartOffset(), scopeNode.startLineStartOffset()); |
3701 | |
3702 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); |
3703 | generator.emitLoad(dstRegister.get(), jsUndefined()); |
3704 | generator.emitProfileControlFlow(scopeNode.startStartOffset()); |
3705 | scopeNode.emitStatementsBytecode(generator, dstRegister.get()); |
3706 | |
3707 | generator.emitDebugHook(DidExecuteProgram, scopeNode.lastLine(), scopeNode.startOffset(), scopeNode.lineStartOffset()); |
3708 | generator.emitEnd(dstRegister.get()); |
3709 | } |
3710 | |
3711 | // ------------------------------ ProgramNode ----------------------------- |
3712 | |
3713 | void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3714 | { |
3715 | emitProgramNodeBytecode(generator, *this); |
3716 | } |
3717 | |
3718 | // ------------------------------ ModuleProgramNode -------------------- |
3719 | |
3720 | void ModuleProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3721 | { |
3722 | emitProgramNodeBytecode(generator, *this); |
3723 | } |
3724 | |
3725 | // ------------------------------ EvalNode ----------------------------- |
3726 | |
3727 | void EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3728 | { |
3729 | generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset()); |
3730 | |
3731 | RefPtr<RegisterID> dstRegister = generator.newTemporary(); |
3732 | generator.emitLoad(dstRegister.get(), jsUndefined()); |
3733 | emitStatementsBytecode(generator, dstRegister.get()); |
3734 | |
3735 | generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); |
3736 | generator.emitEnd(dstRegister.get()); |
3737 | } |
3738 | |
3739 | // ------------------------------ FunctionNode ----------------------------- |
3740 | |
3741 | void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3742 | { |
3743 | if (generator.shouldEmitTypeProfilerHooks()) { |
3744 | // If the parameter list is non simple one, it is handled in bindValue's code. |
3745 | if (m_parameters->isSimpleParameterList()) { |
3746 | for (size_t i = 0; i < m_parameters->size(); i++) { |
3747 | BindingNode* bindingNode = static_cast<BindingNode*>(m_parameters->at(i).first); |
3748 | RegisterID reg(CallFrame::argumentOffset(i)); |
3749 | generator.emitProfileType(®, ProfileTypeBytecodeFunctionArgument, bindingNode->divotStart(), bindingNode->divotEnd()); |
3750 | } |
3751 | } |
3752 | } |
3753 | |
3754 | generator.emitProfileControlFlow(startStartOffset()); |
3755 | generator.emitDebugHook(DidEnterCallFrame, startLine(), startStartOffset(), startLineStartOffset()); |
3756 | |
3757 | switch (generator.parseMode()) { |
3758 | case SourceParseMode::GeneratorWrapperFunctionMode: |
3759 | case SourceParseMode::GeneratorWrapperMethodMode: |
3760 | case SourceParseMode::AsyncGeneratorWrapperMethodMode: |
3761 | case SourceParseMode::AsyncGeneratorWrapperFunctionMode: { |
3762 | StatementNode* singleStatement = this->singleStatement(); |
3763 | ASSERT(singleStatement->isExprStatement()); |
3764 | ExprStatementNode* exprStatement = static_cast<ExprStatementNode*>(singleStatement); |
3765 | ExpressionNode* expr = exprStatement->expr(); |
3766 | ASSERT(expr->isFuncExprNode()); |
3767 | FuncExprNode* funcExpr = static_cast<FuncExprNode*>(expr); |
3768 | |
3769 | RefPtr<RegisterID> next = generator.newTemporary(); |
3770 | generator.emitNode(next.get(), funcExpr); |
3771 | |
3772 | if (generator.superBinding() == SuperBinding::Needed) { |
3773 | RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator); |
3774 | emitPutHomeObject(generator, next.get(), homeObject.get()); |
3775 | } |
3776 | |
3777 | if (isGeneratorWrapperParseMode(generator.parseMode())) |
3778 | generator.emitPutGeneratorFields(next.get()); |
3779 | else { |
3780 | ASSERT(isAsyncGeneratorWrapperParseMode(generator.parseMode())); |
3781 | generator.emitPutAsyncGeneratorFields(next.get()); |
3782 | } |
3783 | |
3784 | ASSERT(startOffset() >= lineStartOffset()); |
3785 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); |
3786 | generator.emitReturn(generator.generatorRegister()); |
3787 | break; |
3788 | } |
3789 | |
3790 | case SourceParseMode::AsyncFunctionMode: |
3791 | case SourceParseMode::AsyncMethodMode: |
3792 | case SourceParseMode::AsyncArrowFunctionMode: { |
3793 | StatementNode* singleStatement = this->singleStatement(); |
3794 | ASSERT(singleStatement->isExprStatement()); |
3795 | ExprStatementNode* exprStatement = static_cast<ExprStatementNode*>(singleStatement); |
3796 | ExpressionNode* expr = exprStatement->expr(); |
3797 | ASSERT(expr->isFuncExprNode()); |
3798 | FuncExprNode* funcExpr = static_cast<FuncExprNode*>(expr); |
3799 | |
3800 | RefPtr<RegisterID> next = generator.newTemporary(); |
3801 | generator.emitNode(next.get(), funcExpr); |
3802 | |
3803 | if (generator.superBinding() == SuperBinding::Needed || (generator.parseMode() == SourceParseMode::AsyncArrowFunctionMode && generator.isSuperUsedInInnerArrowFunction())) { |
3804 | RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator); |
3805 | emitPutHomeObject(generator, next.get(), homeObject.get()); |
3806 | } |
3807 | |
3808 | if (generator.parseMode() == SourceParseMode::AsyncArrowFunctionMode && generator.isThisUsedInInnerArrowFunction()) |
3809 | generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); |
3810 | |
3811 | generator.emitPutGeneratorFields(next.get()); |
3812 | |
3813 | ASSERT(startOffset() >= lineStartOffset()); |
3814 | generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); |
3815 | |
3816 | // load and call @asyncFunctionResume |
3817 | auto var = generator.variable(generator.propertyNames().builtinNames().asyncFunctionResumePrivateName()); |
3818 | RefPtr<RegisterID> scope = generator.newTemporary(); |
3819 | generator.move(scope.get(), generator.emitResolveScope(scope.get(), var)); |
3820 | RefPtr<RegisterID> asyncFunctionResume = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
3821 | |
3822 | CallArguments args(generator, nullptr, 4); |
3823 | unsigned argumentCount = 0; |
3824 | generator.emitLoad(args.thisRegister(), jsUndefined()); |
3825 | generator.move(args.argumentRegister(argumentCount++), generator.generatorRegister()); |
3826 | generator.move(args.argumentRegister(argumentCount++), generator.promiseCapabilityRegister()); |
3827 | generator.emitLoad(args.argumentRegister(argumentCount++), jsUndefined()); |
3828 | generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))); |
3829 | // JSTextPosition(int _line, int _offset, int _lineStartOffset) |
3830 | JSTextPosition divot(firstLine(), startOffset(), lineStartOffset()); |
3831 | |
3832 | RefPtr<RegisterID> result = generator.newTemporary(); |
3833 | generator.emitCallInTailPosition(result.get(), asyncFunctionResume.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No); |
3834 | generator.emitReturn(result.get()); |
3835 | break; |
3836 | } |
3837 | |
3838 | case SourceParseMode::AsyncGeneratorBodyMode: |
3839 | case SourceParseMode::AsyncArrowFunctionBodyMode: |
3840 | case SourceParseMode::AsyncFunctionBodyMode: |
3841 | case SourceParseMode::GeneratorBodyMode: { |
3842 | Ref<Label> generatorBodyLabel = generator.newLabel(); |
3843 | { |
3844 | RefPtr<RegisterID> condition = generator.newTemporary(); |
3845 | generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)))); |
3846 | generator.emitJumpIfTrue(condition.get(), generatorBodyLabel.get()); |
3847 | |
3848 | Ref<Label> throwLabel = generator.newLabel(); |
3849 | generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode)))); |
3850 | generator.emitJumpIfTrue(condition.get(), throwLabel.get()); |
3851 | |
3852 | generator.emitReturn(generator.generatorValueRegister()); |
3853 | |
3854 | generator.emitLabel(throwLabel.get()); |
3855 | generator.emitThrow(generator.generatorValueRegister()); |
3856 | } |
3857 | |
3858 | generator.emitLabel(generatorBodyLabel.get()); |
3859 | |
3860 | emitStatementsBytecode(generator, generator.ignoredResult()); |
3861 | |
3862 | Ref<Label> done = generator.newLabel(); |
3863 | generator.emitLabel(done.get()); |
3864 | generator.emitReturn(generator.emitLoad(nullptr, jsUndefined())); |
3865 | break; |
3866 | } |
3867 | |
3868 | default: { |
3869 | emitStatementsBytecode(generator, generator.ignoredResult()); |
3870 | |
3871 | StatementNode* singleStatement = this->singleStatement(); |
3872 | ReturnNode* returnNode = 0; |
3873 | |
3874 | // Check for a return statement at the end of a function composed of a single block. |
3875 | if (singleStatement && singleStatement->isBlock()) { |
3876 | StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); |
3877 | if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) |
3878 | returnNode = static_cast<ReturnNode*>(lastStatementInBlock); |
3879 | } |
3880 | |
3881 | // If there is no return we must automatically insert one. |
3882 | if (!returnNode) { |
3883 | if (generator.constructorKind() == ConstructorKind::Extends && generator.needsToUpdateArrowFunctionContext() && generator.isSuperCallUsedInInnerArrowFunction()) |
3884 | generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); // Arrow function can invoke 'super' in constructor and before leave constructor we need load 'this' from lexical arrow function environment |
3885 | |
3886 | RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); |
3887 | generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code. |
3888 | ASSERT(startOffset() >= lineStartOffset()); |
3889 | generator.emitWillLeaveCallFrameDebugHook(); |
3890 | generator.emitReturn(r0); |
3891 | return; |
3892 | } |
3893 | break; |
3894 | } |
3895 | } |
3896 | } |
3897 | |
3898 | // ------------------------------ FuncDeclNode --------------------------------- |
3899 | |
3900 | void FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3901 | { |
3902 | generator.hoistSloppyModeFunctionIfNecessary(metadata()->ident()); |
3903 | } |
3904 | |
3905 | // ------------------------------ FuncExprNode --------------------------------- |
3906 | |
3907 | RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3908 | { |
3909 | return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); |
3910 | } |
3911 | |
3912 | // ------------------------------ ArrowFuncExprNode --------------------------------- |
3913 | |
3914 | RegisterID* ArrowFuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3915 | { |
3916 | return generator.emitNewArrowFunctionExpression(generator.finalDestination(dst), this); |
3917 | } |
3918 | |
3919 | // ------------------------------ MethodDefinitionNode --------------------------------- |
3920 | |
3921 | RegisterID* MethodDefinitionNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3922 | { |
3923 | return generator.emitNewMethodDefinition(generator.finalDestination(dst), this); |
3924 | } |
3925 | |
3926 | // ------------------------------ YieldExprNode -------------------------------- |
3927 | |
3928 | RegisterID* YieldExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3929 | { |
3930 | if (!delegate()) { |
3931 | RefPtr<RegisterID> arg = nullptr; |
3932 | if (argument()) { |
3933 | arg = generator.newTemporary(); |
3934 | generator.emitNode(arg.get(), argument()); |
3935 | } else |
3936 | arg = generator.emitLoad(nullptr, jsUndefined()); |
3937 | RefPtr<RegisterID> value = generator.emitYield(arg.get(), JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Yield); |
3938 | if (dst == generator.ignoredResult()) |
3939 | return nullptr; |
3940 | return generator.move(generator.finalDestination(dst), value.get()); |
3941 | } |
3942 | RefPtr<RegisterID> arg = generator.newTemporary(); |
3943 | generator.emitNode(arg.get(), argument()); |
3944 | RefPtr<RegisterID> value = generator.emitDelegateYield(arg.get(), this); |
3945 | if (dst == generator.ignoredResult()) |
3946 | return nullptr; |
3947 | return generator.move(generator.finalDestination(dst), value.get()); |
3948 | } |
3949 | |
3950 | // ------------------------------ AwaitExprNode -------------------------------- |
3951 | |
3952 | RegisterID* AwaitExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3953 | { |
3954 | RefPtr<RegisterID> arg = generator.newTemporary(); |
3955 | generator.emitNode(arg.get(), argument()); |
3956 | RefPtr<RegisterID> value = generator.emitYield(arg.get(), JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Await); |
3957 | if (dst == generator.ignoredResult()) |
3958 | return nullptr; |
3959 | return generator.move(generator.finalDestination(dst), value.get()); |
3960 | } |
3961 | |
3962 | // ------------------------------ ClassDeclNode --------------------------------- |
3963 | |
3964 | void ClassDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) |
3965 | { |
3966 | generator.emitNode(m_classDeclaration); |
3967 | } |
3968 | |
3969 | // ------------------------------ ClassExprNode --------------------------------- |
3970 | |
3971 | RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
3972 | { |
3973 | if (!m_name.isNull()) |
3974 | generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested); |
3975 | |
3976 | RefPtr<RegisterID> superclass; |
3977 | if (m_classHeritage) { |
3978 | superclass = generator.newTemporary(); |
3979 | generator.emitNode(superclass.get(), m_classHeritage); |
3980 | } |
3981 | |
3982 | RefPtr<RegisterID> constructor = generator.tempDestination(dst); |
3983 | bool needsHomeObject = false; |
3984 | |
3985 | if (m_constructorExpression) { |
3986 | ASSERT(m_constructorExpression->isFuncExprNode()); |
3987 | FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(m_constructorExpression)->metadata(); |
3988 | metadata->setEcmaName(ecmaName()); |
3989 | metadata->setClassSource(m_classSource); |
3990 | constructor = generator.emitNode(constructor.get(), m_constructorExpression); |
3991 | needsHomeObject = m_classHeritage || metadata->superBinding() == SuperBinding::Needed; |
3992 | } else |
3993 | constructor = generator.emitNewDefaultConstructor(constructor.get(), m_classHeritage ? ConstructorKind::Extends : ConstructorKind::Base, m_name, ecmaName(), m_classSource); |
3994 | |
3995 | const auto& propertyNames = generator.propertyNames(); |
3996 | RefPtr<RegisterID> prototype = generator.emitNewObject(generator.newTemporary()); |
3997 | |
3998 | if (superclass) { |
3999 | RefPtr<RegisterID> protoParent = generator.newTemporary(); |
4000 | generator.emitLoad(protoParent.get(), jsNull()); |
4001 | |
4002 | RefPtr<RegisterID> tempRegister = generator.newTemporary(); |
4003 | |
4004 | // FIXME: Throw TypeError if it's a generator function. |
4005 | Ref<Label> superclassIsUndefinedLabel = generator.newLabel(); |
4006 | generator.emitJumpIfTrue(generator.emitIsUndefined(tempRegister.get(), superclass.get()), superclassIsUndefinedLabel.get()); |
4007 | |
4008 | Ref<Label> superclassIsNullLabel = generator.newLabel(); |
4009 | generator.emitJumpIfTrue(generator.emitUnaryOp<OpEqNull>(tempRegister.get(), superclass.get()), superclassIsNullLabel.get()); |
4010 | |
4011 | Ref<Label> superclassIsObjectLabel = generator.newLabel(); |
4012 | generator.emitJumpIfTrue(generator.emitIsObject(tempRegister.get(), superclass.get()), superclassIsObjectLabel.get()); |
4013 | generator.emitLabel(superclassIsUndefinedLabel.get()); |
4014 | generator.emitThrowTypeError("The superclass is not an object."_s ); |
4015 | generator.emitLabel(superclassIsObjectLabel.get()); |
4016 | generator.emitGetById(protoParent.get(), superclass.get(), generator.propertyNames().prototype); |
4017 | |
4018 | Ref<Label> protoParentIsObjectOrNullLabel = generator.newLabel(); |
4019 | generator.emitJumpIfTrue(generator.emitUnaryOp<OpIsObjectOrNull>(tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get()); |
4020 | generator.emitJumpIfTrue(generator.emitUnaryOp<OpIsFunction>(tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get()); |
4021 | generator.emitThrowTypeError("The value of the superclass's prototype property is not an object."_s ); |
4022 | generator.emitLabel(protoParentIsObjectOrNullLabel.get()); |
4023 | |
4024 | generator.emitDirectPutById(constructor.get(), generator.propertyNames().underscoreProto, superclass.get(), PropertyNode::Unknown); |
4025 | generator.emitLabel(superclassIsNullLabel.get()); |
4026 | generator.emitDirectPutById(prototype.get(), generator.propertyNames().underscoreProto, protoParent.get(), PropertyNode::Unknown); |
4027 | } |
4028 | |
4029 | if (needsHomeObject) |
4030 | emitPutHomeObject(generator, constructor.get(), prototype.get()); |
4031 | |
4032 | RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(nullptr, propertyNames.constructor); |
4033 | generator.emitCallDefineProperty(prototype.get(), constructorNameRegister.get(), constructor.get(), nullptr, nullptr, |
4034 | BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); |
4035 | |
4036 | RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(nullptr, propertyNames.prototype); |
4037 | generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position); |
4038 | |
4039 | if (m_classElements) |
4040 | generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get()); |
4041 | |
4042 | if (!m_name.isNull()) { |
4043 | Variable classNameVar = generator.variable(m_name); |
4044 | RELEASE_ASSERT(classNameVar.isResolved()); |
4045 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar); |
4046 | generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization); |
4047 | generator.popLexicalScope(this); |
4048 | } |
4049 | |
4050 | return generator.move(generator.finalDestination(dst, constructor.get()), constructor.get()); |
4051 | } |
4052 | |
4053 | // ------------------------------ ImportDeclarationNode ----------------------- |
4054 | |
4055 | void ImportDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
4056 | { |
4057 | // Do nothing at runtime. |
4058 | } |
4059 | |
4060 | // ------------------------------ ExportAllDeclarationNode -------------------- |
4061 | |
4062 | void ExportAllDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
4063 | { |
4064 | // Do nothing at runtime. |
4065 | } |
4066 | |
4067 | // ------------------------------ ExportDefaultDeclarationNode ---------------- |
4068 | |
4069 | void ExportDefaultDeclarationNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
4070 | { |
4071 | ASSERT(m_declaration); |
4072 | generator.emitNode(dst, m_declaration); |
4073 | } |
4074 | |
4075 | // ------------------------------ ExportLocalDeclarationNode ------------------ |
4076 | |
4077 | void ExportLocalDeclarationNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
4078 | { |
4079 | ASSERT(m_declaration); |
4080 | generator.emitNode(dst, m_declaration); |
4081 | } |
4082 | |
4083 | // ------------------------------ ExportNamedDeclarationNode ------------------ |
4084 | |
4085 | void ExportNamedDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
4086 | { |
4087 | // Do nothing at runtime. |
4088 | } |
4089 | |
4090 | // ------------------------------ DestructuringAssignmentNode ----------------- |
4091 | RegisterID* DestructuringAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
4092 | { |
4093 | if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer)) |
4094 | return result; |
4095 | RefPtr<RegisterID> initializer = generator.tempDestination(dst); |
4096 | generator.emitNode(initializer.get(), m_initializer); |
4097 | m_bindings->bindValue(generator, initializer.get()); |
4098 | return generator.move(dst, initializer.get()); |
4099 | } |
4100 | |
4101 | static void assignDefaultValueIfUndefined(BytecodeGenerator& generator, RegisterID* maybeUndefined, ExpressionNode* defaultValue) |
4102 | { |
4103 | ASSERT(defaultValue); |
4104 | Ref<Label> isNotUndefined = generator.newLabel(); |
4105 | generator.emitJumpIfFalse(generator.emitIsUndefined(generator.newTemporary(), maybeUndefined), isNotUndefined.get()); |
4106 | generator.emitNode(maybeUndefined, defaultValue); |
4107 | generator.emitLabel(isNotUndefined.get()); |
4108 | } |
4109 | |
4110 | void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const |
4111 | { |
4112 | RefPtr<RegisterID> iterator = generator.newTemporary(); |
4113 | { |
4114 | generator.emitGetById(iterator.get(), rhs, generator.propertyNames().iteratorSymbol); |
4115 | CallArguments args(generator, nullptr); |
4116 | generator.move(args.thisRegister(), rhs); |
4117 | generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
4118 | } |
4119 | RefPtr<RegisterID> nextMethod = generator.emitGetById(generator.newTemporary(), iterator.get(), generator.propertyNames().next); |
4120 | |
4121 | if (m_targetPatterns.isEmpty()) { |
4122 | generator.emitIteratorClose(iterator.get(), this); |
4123 | return; |
4124 | } |
4125 | |
4126 | RefPtr<RegisterID> done; |
4127 | for (auto& target : m_targetPatterns) { |
4128 | switch (target.bindingType) { |
4129 | case BindingType::Elision: |
4130 | case BindingType::Element: { |
4131 | Ref<Label> iterationSkipped = generator.newLabel(); |
4132 | if (!done) |
4133 | done = generator.newTemporary(); |
4134 | else |
4135 | generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); |
4136 | |
4137 | RefPtr<RegisterID> value = generator.newTemporary(); |
4138 | generator.emitIteratorNext(value.get(), nextMethod.get(), iterator.get(), this); |
4139 | generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); |
4140 | generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); |
4141 | generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); |
4142 | |
4143 | { |
4144 | Ref<Label> valueIsSet = generator.newLabel(); |
4145 | generator.emitJump(valueIsSet.get()); |
4146 | generator.emitLabel(iterationSkipped.get()); |
4147 | generator.emitLoad(value.get(), jsUndefined()); |
4148 | generator.emitLabel(valueIsSet.get()); |
4149 | } |
4150 | |
4151 | if (target.bindingType == BindingType::Element) { |
4152 | if (target.defaultValue) |
4153 | assignDefaultValueIfUndefined(generator, value.get(), target.defaultValue); |
4154 | target.pattern->bindValue(generator, value.get()); |
4155 | } |
4156 | break; |
4157 | } |
4158 | |
4159 | case BindingType::RestElement: { |
4160 | RefPtr<RegisterID> array = generator.emitNewArray(generator.newTemporary(), nullptr, 0, ArrayWithUndecided); |
4161 | |
4162 | Ref<Label> iterationDone = generator.newLabel(); |
4163 | if (!done) |
4164 | done = generator.newTemporary(); |
4165 | else |
4166 | generator.emitJumpIfTrue(done.get(), iterationDone.get()); |
4167 | |
4168 | RefPtr<RegisterID> index = generator.newTemporary(); |
4169 | generator.emitLoad(index.get(), jsNumber(0)); |
4170 | Ref<Label> loopStart = generator.newLabel(); |
4171 | generator.emitLabel(loopStart.get()); |
4172 | |
4173 | RefPtr<RegisterID> value = generator.newTemporary(); |
4174 | generator.emitIteratorNext(value.get(), nextMethod.get(), iterator.get(), this); |
4175 | generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); |
4176 | generator.emitJumpIfTrue(done.get(), iterationDone.get()); |
4177 | generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); |
4178 | |
4179 | generator.emitDirectPutByVal(array.get(), index.get(), value.get()); |
4180 | generator.emitInc(index.get()); |
4181 | generator.emitJump(loopStart.get()); |
4182 | |
4183 | generator.emitLabel(iterationDone.get()); |
4184 | target.pattern->bindValue(generator, array.get()); |
4185 | break; |
4186 | } |
4187 | } |
4188 | } |
4189 | |
4190 | Ref<Label> iteratorClosed = generator.newLabel(); |
4191 | generator.emitJumpIfTrue(done.get(), iteratorClosed.get()); |
4192 | generator.emitIteratorClose(iterator.get(), this); |
4193 | generator.emitLabel(iteratorClosed.get()); |
4194 | } |
4195 | |
4196 | RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs) |
4197 | { |
4198 | if (!rhs->isSimpleArray()) |
4199 | return nullptr; |
4200 | |
4201 | ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements(); |
4202 | Vector<ExpressionNode*> elements; |
4203 | for (; elementNodes; elementNodes = elementNodes->next()) { |
4204 | ExpressionNode* value = elementNodes->value(); |
4205 | if (value->isSpreadExpression()) |
4206 | return nullptr; |
4207 | elements.append(value); |
4208 | } |
4209 | |
4210 | RefPtr<RegisterID> resultRegister; |
4211 | if (dst != generator.ignoredResult()) |
4212 | resultRegister = generator.emitNewArray(generator.newTemporary(), nullptr, 0, ArrayWithUndecided); |
4213 | if (m_targetPatterns.size() != elements.size()) |
4214 | return nullptr; |
4215 | Vector<RefPtr<RegisterID>> registers; |
4216 | registers.reserveCapacity(m_targetPatterns.size()); |
4217 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4218 | registers.uncheckedAppend(generator.newTemporary()); |
4219 | generator.emitNode(registers.last().get(), elements[i]); |
4220 | if (m_targetPatterns[i].defaultValue) |
4221 | assignDefaultValueIfUndefined(generator, registers.last().get(), m_targetPatterns[i].defaultValue); |
4222 | if (resultRegister) { |
4223 | RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(i)); |
4224 | generator.emitDirectPutByVal(resultRegister.get(), index.get(), registers.last().get()); |
4225 | } |
4226 | } |
4227 | |
4228 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4229 | if (m_targetPatterns[i].pattern) |
4230 | m_targetPatterns[i].pattern->bindValue(generator, registers[i].get()); |
4231 | } |
4232 | if (resultRegister) |
4233 | return generator.move(generator.finalDestination(dst, resultRegister.get()), resultRegister.get()); |
4234 | return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); |
4235 | } |
4236 | |
4237 | void ArrayPatternNode::toString(StringBuilder& builder) const |
4238 | { |
4239 | builder.append('['); |
4240 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4241 | const auto& target = m_targetPatterns[i]; |
4242 | |
4243 | switch (target.bindingType) { |
4244 | case BindingType::Elision: |
4245 | builder.append(','); |
4246 | break; |
4247 | |
4248 | case BindingType::Element: |
4249 | target.pattern->toString(builder); |
4250 | if (i < m_targetPatterns.size() - 1) |
4251 | builder.append(','); |
4252 | break; |
4253 | |
4254 | case BindingType::RestElement: |
4255 | builder.appendLiteral("..." ); |
4256 | target.pattern->toString(builder); |
4257 | break; |
4258 | } |
4259 | } |
4260 | builder.append(']'); |
4261 | } |
4262 | |
4263 | void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const |
4264 | { |
4265 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4266 | if (DestructuringPatternNode* node = m_targetPatterns[i].pattern) |
4267 | node->collectBoundIdentifiers(identifiers); |
4268 | } |
4269 | } |
4270 | |
4271 | void ObjectPatternNode::toString(StringBuilder& builder) const |
4272 | { |
4273 | builder.append('{'); |
4274 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4275 | if (m_targetPatterns[i].wasString) |
4276 | builder.appendQuotedJSONString(m_targetPatterns[i].propertyName.string()); |
4277 | else |
4278 | builder.append(m_targetPatterns[i].propertyName.string()); |
4279 | builder.append(':'); |
4280 | m_targetPatterns[i].pattern->toString(builder); |
4281 | if (i < m_targetPatterns.size() - 1) |
4282 | builder.append(','); |
4283 | } |
4284 | builder.append('}'); |
4285 | } |
4286 | |
4287 | void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const |
4288 | { |
4289 | generator.emitRequireObjectCoercible(rhs, "Right side of assignment cannot be destructured"_s ); |
4290 | |
4291 | RefPtr<RegisterID> excludedList; |
4292 | IdentifierSet excludedSet; |
4293 | RefPtr<RegisterID> addMethod; |
4294 | if (m_containsRestElement && m_containsComputedProperty) { |
4295 | auto var = generator.variable(generator.propertyNames().builtinNames().SetPrivateName()); |
4296 | |
4297 | RefPtr<RegisterID> scope = generator.newTemporary(); |
4298 | generator.move(scope.get(), generator.emitResolveScope(scope.get(), var)); |
4299 | RefPtr<RegisterID> setConstructor = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
4300 | |
4301 | CallArguments args(generator, nullptr, 0); |
4302 | excludedList = generator.emitConstruct(generator.newTemporary(), setConstructor.get(), setConstructor.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd()); |
4303 | |
4304 | addMethod = generator.emitGetById(generator.newTemporary(), excludedList.get(), generator.propertyNames().builtinNames().addPrivateName()); |
4305 | } |
4306 | |
4307 | for (size_t i = 0; i < m_targetPatterns.size(); i++) { |
4308 | const auto& target = m_targetPatterns[i]; |
4309 | if (target.bindingType == BindingType::Element) { |
4310 | RefPtr<RegisterID> temp = generator.newTemporary(); |
4311 | RefPtr<RegisterID> propertyName; |
4312 | if (!target.propertyExpression) { |
4313 | Optional<uint32_t> optionalIndex = parseIndex(target.propertyName); |
4314 | if (!optionalIndex) |
4315 | generator.emitGetById(temp.get(), rhs, target.propertyName); |
4316 | else { |
4317 | RefPtr<RegisterID> propertyIndex = generator.emitLoad(nullptr, jsNumber(optionalIndex.value())); |
4318 | generator.emitGetByVal(temp.get(), rhs, propertyIndex.get()); |
4319 | } |
4320 | } else { |
4321 | propertyName = generator.emitNodeForProperty(target.propertyExpression); |
4322 | generator.emitGetByVal(temp.get(), rhs, propertyName.get()); |
4323 | } |
4324 | |
4325 | if (m_containsRestElement) { |
4326 | if (m_containsComputedProperty) { |
4327 | if (!target.propertyExpression) |
4328 | propertyName = generator.emitLoad(nullptr, target.propertyName); |
4329 | |
4330 | CallArguments args(generator, nullptr, 1); |
4331 | generator.move(args.thisRegister(), excludedList.get()); |
4332 | generator.move(args.argumentRegister(0), propertyName.get()); |
4333 | generator.emitCall(generator.newTemporary(), addMethod.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
4334 | } else |
4335 | excludedSet.add(target.propertyName.impl()); |
4336 | } |
4337 | |
4338 | if (target.defaultValue) |
4339 | assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue); |
4340 | target.pattern->bindValue(generator, temp.get()); |
4341 | } else { |
4342 | ASSERT(target.bindingType == BindingType::RestElement); |
4343 | ASSERT(i == m_targetPatterns.size() - 1); |
4344 | RefPtr<RegisterID> newObject = generator.emitNewObject(generator.newTemporary()); |
4345 | |
4346 | // load and call @copyDataProperties |
4347 | auto var = generator.variable(generator.propertyNames().builtinNames().copyDataPropertiesPrivateName()); |
4348 | |
4349 | RefPtr<RegisterID> scope = generator.newTemporary(); |
4350 | generator.move(scope.get(), generator.emitResolveScope(scope.get(), var)); |
4351 | RefPtr<RegisterID> copyDataProperties = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
4352 | |
4353 | CallArguments args(generator, nullptr, 3); |
4354 | generator.emitLoad(args.thisRegister(), jsUndefined()); |
4355 | generator.move(args.argumentRegister(0), newObject.get()); |
4356 | generator.move(args.argumentRegister(1), rhs); |
4357 | if (m_containsComputedProperty) |
4358 | generator.move(args.argumentRegister(2), excludedList.get()); |
4359 | else { |
4360 | RefPtr<RegisterID> excludedSetReg = generator.emitLoad(generator.newTemporary(), excludedSet); |
4361 | generator.move(args.argumentRegister(2), excludedSetReg.get()); |
4362 | } |
4363 | |
4364 | RefPtr<RegisterID> result = generator.newTemporary(); |
4365 | generator.emitCall(result.get(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
4366 | target.pattern->bindValue(generator, result.get()); |
4367 | } |
4368 | } |
4369 | } |
4370 | |
4371 | void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const |
4372 | { |
4373 | for (size_t i = 0; i < m_targetPatterns.size(); i++) |
4374 | m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers); |
4375 | } |
4376 | |
4377 | void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const |
4378 | { |
4379 | Variable var = generator.variable(m_boundProperty); |
4380 | bool isReadOnly = var.isReadOnly() && m_bindingContext != AssignmentContext::ConstDeclarationStatement; |
4381 | if (RegisterID* local = var.local()) { |
4382 | if (m_bindingContext == AssignmentContext::AssignmentExpression) |
4383 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
4384 | if (isReadOnly) { |
4385 | generator.emitReadOnlyExceptionIfNeeded(var); |
4386 | return; |
4387 | } |
4388 | generator.move(local, value); |
4389 | generator.emitProfileType(local, var, divotStart(), divotEnd()); |
4390 | if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement) |
4391 | generator.liftTDZCheckIfPossible(var); |
4392 | return; |
4393 | } |
4394 | if (generator.isStrictMode()) |
4395 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4396 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
4397 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4398 | if (m_bindingContext == AssignmentContext::AssignmentExpression) |
4399 | generator.emitTDZCheckIfNecessary(var, nullptr, scope.get()); |
4400 | if (isReadOnly) { |
4401 | generator.emitReadOnlyExceptionIfNeeded(var); |
4402 | return; |
4403 | } |
4404 | generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, initializationModeForAssignmentContext(m_bindingContext)); |
4405 | generator.emitProfileType(value, var, divotStart(), divotEnd()); |
4406 | if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement) |
4407 | generator.liftTDZCheckIfPossible(var); |
4408 | return; |
4409 | } |
4410 | |
4411 | void BindingNode::toString(StringBuilder& builder) const |
4412 | { |
4413 | builder.append(m_boundProperty.string()); |
4414 | } |
4415 | |
4416 | void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const |
4417 | { |
4418 | identifiers.append(m_boundProperty); |
4419 | } |
4420 | |
4421 | void AssignmentElementNode::collectBoundIdentifiers(Vector<Identifier>&) const |
4422 | { |
4423 | } |
4424 | |
4425 | void AssignmentElementNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const |
4426 | { |
4427 | if (m_assignmentTarget->isResolveNode()) { |
4428 | ResolveNode* lhs = static_cast<ResolveNode*>(m_assignmentTarget); |
4429 | Variable var = generator.variable(lhs->identifier()); |
4430 | bool isReadOnly = var.isReadOnly(); |
4431 | if (RegisterID* local = var.local()) { |
4432 | generator.emitTDZCheckIfNecessary(var, local, nullptr); |
4433 | |
4434 | if (isReadOnly) |
4435 | generator.emitReadOnlyExceptionIfNeeded(var); |
4436 | else { |
4437 | generator.move(local, value); |
4438 | generator.emitProfileType(local, divotStart(), divotEnd()); |
4439 | } |
4440 | return; |
4441 | } |
4442 | if (generator.isStrictMode()) |
4443 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4444 | RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); |
4445 | generator.emitTDZCheckIfNecessary(var, nullptr, scope.get()); |
4446 | if (isReadOnly) { |
4447 | bool threwException = generator.emitReadOnlyExceptionIfNeeded(var); |
4448 | if (threwException) |
4449 | return; |
4450 | } |
4451 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4452 | if (!isReadOnly) { |
4453 | generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::NotInitialization); |
4454 | generator.emitProfileType(value, var, divotStart(), divotEnd()); |
4455 | } |
4456 | } else if (m_assignmentTarget->isDotAccessorNode()) { |
4457 | DotAccessorNode* lhs = static_cast<DotAccessorNode*>(m_assignmentTarget); |
4458 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false); |
4459 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4460 | if (lhs->base()->isSuperNode()) { |
4461 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
4462 | generator.emitPutById(base.get(), thisValue.get(), lhs->identifier(), value); |
4463 | } else |
4464 | generator.emitPutById(base.get(), lhs->identifier(), value); |
4465 | generator.emitProfileType(value, divotStart(), divotEnd()); |
4466 | } else if (m_assignmentTarget->isBracketAccessorNode()) { |
4467 | BracketAccessorNode* lhs = static_cast<BracketAccessorNode*>(m_assignmentTarget); |
4468 | RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false); |
4469 | RefPtr<RegisterID> property = generator.emitNodeForLeftHandSideForProperty(lhs->subscript(), true, false); |
4470 | generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); |
4471 | if (lhs->base()->isSuperNode()) { |
4472 | RefPtr<RegisterID> thisValue = generator.ensureThis(); |
4473 | generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value); |
4474 | } else |
4475 | generator.emitPutByVal(base.get(), property.get(), value); |
4476 | generator.emitProfileType(value, divotStart(), divotEnd()); |
4477 | } |
4478 | } |
4479 | |
4480 | void AssignmentElementNode::toString(StringBuilder& builder) const |
4481 | { |
4482 | if (m_assignmentTarget->isResolveNode()) |
4483 | builder.append(static_cast<ResolveNode*>(m_assignmentTarget)->identifier().string()); |
4484 | } |
4485 | |
4486 | void RestParameterNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const |
4487 | { |
4488 | m_pattern->collectBoundIdentifiers(identifiers); |
4489 | } |
4490 | |
4491 | void RestParameterNode::toString(StringBuilder& builder) const |
4492 | { |
4493 | builder.appendLiteral("..." ); |
4494 | m_pattern->toString(builder); |
4495 | } |
4496 | |
4497 | void RestParameterNode::bindValue(BytecodeGenerator&, RegisterID*) const |
4498 | { |
4499 | RELEASE_ASSERT_NOT_REACHED(); |
4500 | } |
4501 | |
4502 | void RestParameterNode::emit(BytecodeGenerator& generator) |
4503 | { |
4504 | RefPtr<RegisterID> temp = generator.newTemporary(); |
4505 | generator.emitRestParameter(temp.get(), m_numParametersToSkip); |
4506 | m_pattern->bindValue(generator, temp.get()); |
4507 | } |
4508 | |
4509 | |
4510 | RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*) |
4511 | { |
4512 | RELEASE_ASSERT_NOT_REACHED(); |
4513 | return 0; |
4514 | } |
4515 | |
4516 | RegisterID* ObjectSpreadExpressionNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) |
4517 | { |
4518 | RefPtr<RegisterID> src = generator.newTemporary(); |
4519 | generator.emitNode(src.get(), m_expression); |
4520 | |
4521 | // load and call @copyDataPropertiesNoExclusions |
4522 | auto var = generator.variable(generator.propertyNames().builtinNames().copyDataPropertiesNoExclusionsPrivateName()); |
4523 | |
4524 | RefPtr<RegisterID> scope = generator.newTemporary(); |
4525 | generator.move(scope.get(), generator.emitResolveScope(scope.get(), var)); |
4526 | RefPtr<RegisterID> copyDataProperties = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); |
4527 | |
4528 | CallArguments args(generator, nullptr, 2); |
4529 | generator.emitLoad(args.thisRegister(), jsUndefined()); |
4530 | generator.move(args.argumentRegister(0), dst); |
4531 | generator.move(args.argumentRegister(1), src.get()); |
4532 | |
4533 | generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No); |
4534 | |
4535 | return dst; |
4536 | } |
4537 | |
4538 | } // namespace JSC |
4539 | |