]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved. |
9dae56ea | 3 | * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> |
93a37866 | 4 | * Copyright (C) 2012 Igalia, S.L. |
9dae56ea A |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
81345200 | 15 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
16 | * its contributors may be used to endorse or promote products derived |
17 | * from this software without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
22 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
31 | #include "config.h" | |
32 | #include "BytecodeGenerator.h" | |
33 | ||
ed1e77d3 | 34 | #include "BuiltinExecutables.h" |
9dae56ea | 35 | #include "Interpreter.h" |
93a37866 | 36 | #include "JSFunction.h" |
ed1e77d3 | 37 | #include "JSLexicalEnvironment.h" |
93a37866 | 38 | #include "JSNameScope.h" |
ed1e77d3 | 39 | #include "JSTemplateRegistryKey.h" |
6fe7ccc8 | 40 | #include "LowLevelInterpreter.h" |
81345200 | 41 | #include "JSCInlines.h" |
93a37866 | 42 | #include "Options.h" |
81345200 | 43 | #include "StackAlignment.h" |
6fe7ccc8 | 44 | #include "StrongInlines.h" |
93a37866 | 45 | #include "UnlinkedCodeBlock.h" |
81345200 A |
46 | #include "UnlinkedInstructionStream.h" |
47 | #include <wtf/StdLibExtras.h> | |
93a37866 | 48 | #include <wtf/text/WTFString.h> |
9dae56ea A |
49 | |
50 | using namespace std; | |
51 | ||
52 | namespace JSC { | |
53 | ||
6fe7ccc8 A |
54 | void Label::setLocation(unsigned location) |
55 | { | |
56 | m_location = location; | |
57 | ||
58 | unsigned size = m_unresolvedJumps.size(); | |
59 | for (unsigned i = 0; i < size; ++i) | |
ed1e77d3 | 60 | m_generator.instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; |
6fe7ccc8 | 61 | } |
9dae56ea | 62 | |
93a37866 | 63 | ParserError BytecodeGenerator::generate() |
9dae56ea | 64 | { |
6fe7ccc8 A |
65 | SamplingRegion samplingRegion("Bytecode Generation"); |
66 | ||
81345200 | 67 | m_codeBlock->setThisRegister(m_thisRegister.virtualRegister()); |
ed1e77d3 A |
68 | |
69 | // If we have declared a variable named "arguments" and we are using arguments then we should | |
70 | // perform that assignment now. | |
71 | if (m_needToInitializeArguments) | |
72 | initializeVariable(variable(propertyNames().arguments), m_argumentsRegister); | |
73 | ||
74 | for (size_t i = 0; i < m_destructuringParameters.size(); i++) { | |
75 | auto& entry = m_destructuringParameters[i]; | |
81345200 A |
76 | entry.second->bindValue(*this, entry.first.get()); |
77 | } | |
9dae56ea | 78 | |
ed1e77d3 A |
79 | { |
80 | RefPtr<RegisterID> temp = newTemporary(); | |
81 | RefPtr<RegisterID> globalScope = scopeRegister(); // FIXME: With lexical scoping, this won't always be the global object: https://bugs.webkit.org/show_bug.cgi?id=142944 | |
82 | for (auto functionPair : m_functionsToInitialize) { | |
83 | FunctionBodyNode* functionBody = functionPair.first; | |
84 | FunctionVariableType functionType = functionPair.second; | |
85 | emitNewFunction(temp.get(), functionBody); | |
86 | if (functionType == NormalFunctionVariable) | |
87 | initializeVariable(variable(functionBody->ident()) , temp.get()); | |
88 | else if (functionType == GlobalFunctionVariable) | |
89 | emitPutToScope(globalScope.get(), Variable(functionBody->ident()), temp.get(), ThrowIfNotFound); | |
90 | else | |
91 | RELEASE_ASSERT_NOT_REACHED(); | |
92 | } | |
93 | } | |
94 | ||
95 | bool callingClassConstructor = constructorKind() != ConstructorKind::None && !isConstructor(); | |
96 | if (!callingClassConstructor) | |
97 | m_scopeNode->emitBytecode(*this); | |
9dae56ea | 98 | |
93a37866 | 99 | m_staticPropertyAnalyzer.kill(); |
9dae56ea | 100 | |
93a37866 A |
101 | for (unsigned i = 0; i < m_tryRanges.size(); ++i) { |
102 | TryRange& range = m_tryRanges[i]; | |
103 | int start = range.start->bind(); | |
104 | int end = range.end->bind(); | |
105 | ||
106 | // This will happen for empty try blocks and for some cases of finally blocks: | |
107 | // | |
108 | // try { | |
109 | // try { | |
110 | // } finally { | |
111 | // return 42; | |
112 | // // *HERE* | |
113 | // } | |
114 | // } finally { | |
115 | // print("things"); | |
116 | // } | |
117 | // | |
118 | // The return will pop scopes to execute the outer finally block. But this includes | |
119 | // popping the try context for the inner try. The try context is live in the fall-through | |
120 | // part of the finally block not because we will emit a handler that overlaps the finally, | |
121 | // but because we haven't yet had a chance to plant the catch target. Then when we finish | |
122 | // emitting code for the outer finally block, we repush the try contex, this time with a | |
123 | // new start index. But that means that the start index for the try range corresponding | |
124 | // to the inner-finally-following-the-return (marked as "*HERE*" above) will be greater | |
125 | // than the end index of the try block. This is harmless since end < start handlers will | |
126 | // never get matched in our logic, but we do the runtime a favor and choose to not emit | |
127 | // such handlers at all. | |
128 | if (end <= start) | |
129 | continue; | |
130 | ||
131 | ASSERT(range.tryData->targetScopeDepth != UINT_MAX); | |
ed1e77d3 A |
132 | ASSERT(range.tryData->handlerType != HandlerType::Illegal); |
133 | UnlinkedHandlerInfo info(static_cast<uint32_t>(start), static_cast<uint32_t>(end), | |
134 | static_cast<uint32_t>(range.tryData->target->bind()), range.tryData->targetScopeDepth, | |
135 | range.tryData->handlerType); | |
93a37866 A |
136 | m_codeBlock->addExceptionHandler(info); |
137 | } | |
138 | ||
81345200 | 139 | m_codeBlock->setInstructions(std::make_unique<UnlinkedInstructionStream>(m_instructions)); |
9dae56ea A |
140 | |
141 | m_codeBlock->shrinkToFit(); | |
14957cd0 | 142 | |
ed1e77d3 A |
143 | if (m_codeBlock->symbolTable() && !m_codeBlock->vm()->typeProfiler()) |
144 | m_codeBlock->setSymbolTable(m_codeBlock->symbolTable()->cloneScopePart(*m_codeBlock->vm())); | |
81345200 | 145 | |
14957cd0 | 146 | if (m_expressionTooDeep) |
93a37866 A |
147 | return ParserError(ParserError::OutOfMemory); |
148 | return ParserError(ParserError::ErrorNone); | |
9dae56ea A |
149 | } |
150 | ||
81345200 A |
151 | BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) |
152 | : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) | |
153 | , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) | |
9dae56ea | 154 | , m_scopeNode(programNode) |
93a37866 | 155 | , m_codeBlock(vm, codeBlock) |
6fe7ccc8 | 156 | , m_thisRegister(CallFrame::thisArgumentOffset()) |
9dae56ea | 157 | , m_codeType(GlobalCode) |
93a37866 | 158 | , m_vm(&vm) |
9dae56ea | 159 | { |
ed1e77d3 A |
160 | for (auto& constantRegister : m_linkTimeConstantRegisters) |
161 | constantRegister = nullptr; | |
162 | ||
6fe7ccc8 | 163 | m_codeBlock->setNumParameters(1); // Allocate space for "this" |
9dae56ea | 164 | |
93a37866 | 165 | emitOpcode(op_enter); |
9dae56ea | 166 | |
ed1e77d3 A |
167 | allocateAndEmitScope(); |
168 | ||
9dae56ea A |
169 | const VarStack& varStack = programNode->varStack(); |
170 | const FunctionStack& functionStack = programNode->functionStack(); | |
14957cd0 | 171 | |
6fe7ccc8 A |
172 | for (size_t i = 0; i < functionStack.size(); ++i) { |
173 | FunctionBodyNode* function = functionStack[i]; | |
ed1e77d3 | 174 | m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable)); |
6fe7ccc8 | 175 | } |
9dae56ea | 176 | |
93a37866 | 177 | for (size_t i = 0; i < varStack.size(); ++i) |
81345200 | 178 | codeBlock->addVariableDeclaration(varStack[i].first, !!(varStack[i].second & DeclarationStacks::IsConstant)); |
93a37866 | 179 | |
9dae56ea A |
180 | } |
181 | ||
ed1e77d3 | 182 | BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) |
81345200 A |
183 | : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) |
184 | , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) | |
93a37866 | 185 | , m_symbolTable(codeBlock->symbolTable()) |
ed1e77d3 | 186 | , m_scopeNode(functionNode) |
93a37866 | 187 | , m_codeBlock(vm, codeBlock) |
9dae56ea | 188 | , m_codeType(FunctionCode) |
93a37866 | 189 | , m_vm(&vm) |
81345200 | 190 | , m_isBuiltinFunction(codeBlock->isBuiltinFunction()) |
9dae56ea | 191 | { |
ed1e77d3 A |
192 | for (auto& constantRegister : m_linkTimeConstantRegisters) |
193 | constantRegister = nullptr; | |
194 | ||
81345200 A |
195 | if (m_isBuiltinFunction) |
196 | m_shouldEmitDebugHooks = false; | |
ed1e77d3 | 197 | |
93a37866 | 198 | m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); |
81345200 | 199 | Vector<Identifier> boundParameterProperties; |
ed1e77d3 | 200 | FunctionParameters& parameters = *functionNode->parameters(); |
81345200 A |
201 | for (size_t i = 0; i < parameters.size(); i++) { |
202 | auto pattern = parameters.at(i); | |
203 | if (pattern->isBindingNode()) | |
204 | continue; | |
205 | pattern->collectBoundIdentifiers(boundParameterProperties); | |
206 | continue; | |
207 | } | |
93a37866 | 208 | |
ed1e77d3 A |
209 | bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain(); |
210 | bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); | |
211 | bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval(); | |
212 | ||
213 | auto captures = [&] (UniquedStringImpl* uid) -> bool { | |
214 | if (shouldCaptureAllOfTheThings) | |
215 | return true; | |
216 | if (!shouldCaptureSomeOfTheThings) | |
217 | return false; | |
218 | if (needsArguments && uid == propertyNames().arguments.impl()) { | |
219 | // Actually, we only need to capture the arguments object when we "need full activation" | |
220 | // because of name scopes. But historically we did it this way, so for now we just preserve | |
221 | // the old behavior. | |
222 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=143072 | |
223 | return true; | |
224 | } | |
225 | return functionNode->captures(uid); | |
226 | }; | |
227 | auto varKind = [&] (UniquedStringImpl* uid) -> VarKind { | |
228 | return captures(uid) ? VarKind::Scope : VarKind::Stack; | |
229 | }; | |
14957cd0 | 230 | |
ed1e77d3 | 231 | emitOpcode(op_enter); |
9dae56ea | 232 | |
ed1e77d3 A |
233 | allocateAndEmitScope(); |
234 | ||
235 | m_calleeRegister.setIndex(JSStack::Callee); | |
236 | ||
237 | if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) | |
238 | && functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode())) { | |
239 | // When we do this, we should make our local scope stack know about the function name symbol | |
240 | // table. Currently this works because bytecode linking creates a phony name scope. | |
241 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141885 | |
242 | // Also, we could create the scope once per JSFunction instance that needs it. That wouldn't | |
243 | // be any more correct, but it would be more performant. | |
244 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141887 | |
245 | emitPushFunctionNameScope(m_scopeRegister, functionNode->ident(), &m_calleeRegister, ReadOnly | DontDelete); | |
ba379fdc | 246 | } |
9dae56ea | 247 | |
ed1e77d3 A |
248 | if (shouldCaptureSomeOfTheThings) { |
249 | m_lexicalEnvironmentRegister = addVar(); | |
250 | m_codeBlock->setActivationRegister(m_lexicalEnvironmentRegister->virtualRegister()); | |
251 | emitOpcode(op_create_lexical_environment); | |
252 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
253 | instructions().append(scopeRegister()->index()); | |
254 | emitOpcode(op_mov); | |
255 | instructions().append(scopeRegister()->index()); | |
256 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
257 | } | |
258 | ||
259 | // Make sure the code block knows about all of our parameters, and make sure that parameters | |
260 | // needing destructuring are noted. | |
261 | m_parameters.grow(parameters.size() + 1); // reserve space for "this" | |
262 | m_thisRegister.setIndex(initializeNextParameter()->index()); // this | |
263 | for (unsigned i = 0; i < parameters.size(); ++i) { | |
264 | auto pattern = parameters.at(i); | |
265 | RegisterID* reg = initializeNextParameter(); | |
266 | if (!pattern->isBindingNode()) | |
267 | m_destructuringParameters.append(std::make_pair(reg, pattern)); | |
268 | } | |
269 | ||
270 | // Figure out some interesting facts about our arguments. | |
93a37866 | 271 | bool capturesAnyArgumentByName = false; |
ed1e77d3 A |
272 | if (functionNode->hasCapturedVariables()) { |
273 | FunctionParameters& parameters = *functionNode->parameters(); | |
93a37866 | 274 | for (size_t i = 0; i < parameters.size(); ++i) { |
81345200 A |
275 | auto pattern = parameters.at(i); |
276 | if (!pattern->isBindingNode()) | |
277 | continue; | |
278 | const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty(); | |
ed1e77d3 | 279 | capturesAnyArgumentByName |= captures(ident.impl()); |
93a37866 A |
280 | } |
281 | } | |
282 | ||
ed1e77d3 A |
283 | if (capturesAnyArgumentByName) |
284 | ASSERT(m_lexicalEnvironmentRegister); | |
285 | ||
286 | // Need to know what our functions are called. Parameters have some goofy behaviors when it | |
287 | // comes to functions of the same name. | |
288 | for (FunctionBodyNode* function : functionNode->functionStack()) | |
289 | m_functions.add(function->ident().impl()); | |
290 | ||
291 | if (needsArguments) { | |
292 | // Create the arguments object now. We may put the arguments object into the activation if | |
293 | // it is captured. Either way, we create two arguments object variables: one is our | |
294 | // private variable that is immutable, and another that is the user-visible variable. The | |
295 | // immutable one is only used here, or during formal parameter resolutions if we opt for | |
296 | // DirectArguments. | |
297 | ||
298 | m_argumentsRegister = addVar(); | |
299 | m_argumentsRegister->ref(); | |
93a37866 | 300 | } |
ed1e77d3 A |
301 | |
302 | if (needsArguments && !codeBlock->isStrictMode()) { | |
303 | // If we captured any formal parameter by name, then we use ScopedArguments. Otherwise we | |
304 | // use DirectArguments. With ScopedArguments, we lift all of our arguments into the | |
305 | // activation. | |
306 | ||
307 | if (capturesAnyArgumentByName) { | |
308 | m_symbolTable->setArgumentsLength(vm, parameters.size()); | |
309 | ||
310 | // For each parameter, we have two possibilities: | |
311 | // Either it's a binding node with no function overlap, in which case it gets a name | |
312 | // in the symbol table - or it just gets space reserved in the symbol table. Either | |
313 | // way we lift the value into the scope. | |
314 | for (unsigned i = 0; i < parameters.size(); ++i) { | |
315 | ScopeOffset offset = m_symbolTable->takeNextScopeOffset(); | |
316 | m_symbolTable->setArgumentOffset(vm, i, offset); | |
317 | if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i))) { | |
318 | VarOffset varOffset(offset); | |
319 | SymbolTableEntry entry(varOffset); | |
320 | // Stores to these variables via the ScopedArguments object will not do | |
321 | // notifyWrite(), since that would be cumbersome. Also, watching formal | |
322 | // parameters when "arguments" is in play is unlikely to be super profitable. | |
323 | // So, we just disable it. | |
324 | entry.disableWatching(); | |
325 | m_symbolTable->set(name, entry); | |
326 | } | |
327 | emitOpcode(op_put_to_scope); | |
328 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
329 | instructions().append(UINT_MAX); | |
330 | instructions().append(virtualRegisterForArgument(1 + i).offset()); | |
331 | instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); | |
332 | instructions().append(0); | |
333 | instructions().append(offset.offset()); | |
14957cd0 | 334 | } |
ed1e77d3 A |
335 | |
336 | // This creates a scoped arguments object and copies the overflow arguments into the | |
337 | // scope. It's the equivalent of calling ScopedArguments::createByCopying(). | |
338 | emitOpcode(op_create_scoped_arguments); | |
339 | instructions().append(m_argumentsRegister->index()); | |
340 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
341 | } else { | |
342 | // We're going to put all parameters into the DirectArguments object. First ensure | |
343 | // that the symbol table knows that this is happening. | |
344 | for (unsigned i = 0; i < parameters.size(); ++i) { | |
345 | if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i))) | |
346 | m_symbolTable->set(name, SymbolTableEntry(VarOffset(DirectArgumentsOffset(i)))); | |
347 | } | |
348 | ||
349 | emitOpcode(op_create_direct_arguments); | |
350 | instructions().append(m_argumentsRegister->index()); | |
14957cd0 | 351 | } |
ed1e77d3 A |
352 | } else { |
353 | // Create the formal parameters the normal way. Any of them could be captured, or not. If | |
354 | // captured, lift them into the scope. | |
355 | for (unsigned i = 0; i < parameters.size(); ++i) { | |
356 | UniquedStringImpl* name = visibleNameForParameter(parameters.at(i)); | |
357 | if (!name) | |
358 | continue; | |
359 | ||
360 | if (!captures(name)) { | |
361 | // This is the easy case - just tell the symbol table about the argument. It will | |
362 | // be accessed directly. | |
363 | m_symbolTable->set(name, SymbolTableEntry(VarOffset(virtualRegisterForArgument(1 + i)))); | |
364 | continue; | |
365 | } | |
366 | ||
367 | ScopeOffset offset = m_symbolTable->takeNextScopeOffset(); | |
368 | const Identifier& ident = | |
369 | static_cast<const BindingNode*>(parameters.at(i))->boundProperty(); | |
370 | m_symbolTable->set(name, SymbolTableEntry(VarOffset(offset))); | |
371 | ||
372 | emitOpcode(op_put_to_scope); | |
373 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
374 | instructions().append(addConstant(ident)); | |
375 | instructions().append(virtualRegisterForArgument(1 + i).offset()); | |
376 | instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); | |
377 | instructions().append(0); | |
378 | instructions().append(offset.offset()); | |
14957cd0 A |
379 | } |
380 | } | |
ed1e77d3 A |
381 | |
382 | if (needsArguments && codeBlock->isStrictMode()) { | |
383 | // Allocate an out-of-bands arguments object. | |
384 | emitOpcode(op_create_out_of_band_arguments); | |
385 | instructions().append(m_argumentsRegister->index()); | |
386 | } | |
387 | ||
388 | // Now declare all variables. | |
389 | for (const Identifier& ident : boundParameterProperties) | |
390 | createVariable(ident, varKind(ident.impl()), IsVariable); | |
391 | for (FunctionBodyNode* function : functionNode->functionStack()) { | |
f9bf01c6 | 392 | const Identifier& ident = function->ident(); |
ed1e77d3 A |
393 | createVariable(ident, varKind(ident.impl()), IsVariable); |
394 | m_functionsToInitialize.append(std::make_pair(function, NormalFunctionVariable)); | |
9dae56ea | 395 | } |
ed1e77d3 A |
396 | for (auto& entry : functionNode->varStack()) { |
397 | ConstantMode constantMode = modeForIsConstant(entry.second & DeclarationStacks::IsConstant); | |
398 | // Variables named "arguments" are never const. | |
399 | if (entry.first == propertyNames().arguments) | |
400 | constantMode = IsVariable; | |
401 | createVariable(entry.first, varKind(entry.first.impl()), constantMode, IgnoreExisting); | |
81345200 | 402 | } |
ed1e77d3 A |
403 | |
404 | // There are some variables that need to be preinitialized to something other than Undefined: | |
405 | // | |
406 | // - "arguments": unless it's used as a function or parameter, this should refer to the | |
407 | // arguments object. | |
408 | // | |
409 | // - callee: unless it's used as a var, function, or parameter, this should refer to the | |
410 | // callee (i.e. our function). | |
411 | // | |
412 | // - functions: these always override everything else. | |
413 | // | |
414 | // The most logical way to do all of this is to initialize none of the variables until now, | |
415 | // and then initialize them in BytecodeGenerator::generate() in such an order that the rules | |
416 | // for how these things override each other end up holding. We would initialize the callee | |
417 | // first, then "arguments", then all arguments, then the functions. | |
418 | // | |
419 | // But some arguments are already initialized by default, since if they aren't captured and we | |
420 | // don't have "arguments" then we just point the symbol table at the stack slot of those | |
421 | // arguments. We end up initializing the rest of the arguments that have an uncomplicated | |
422 | // binding (i.e. don't involve destructuring) above when figuring out how to lay them out, | |
423 | // because that's just the simplest thing. This means that when we initialize them, we have to | |
424 | // watch out for the things that override arguments (namely, functions). | |
425 | // | |
426 | // We also initialize callee here as well, just because it's so weird. We know whether we want | |
427 | // to do this because we can just check if it's in the symbol table. | |
428 | if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) | |
429 | && !functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode()) | |
430 | && m_symbolTable->get(functionNode->ident().impl()).isNull()) { | |
431 | if (captures(functionNode->ident().impl())) { | |
432 | ScopeOffset offset; | |
433 | { | |
434 | ConcurrentJITLocker locker(m_symbolTable->m_lock); | |
435 | offset = m_symbolTable->takeNextScopeOffset(locker); | |
436 | m_symbolTable->add( | |
437 | locker, functionNode->ident().impl(), | |
438 | SymbolTableEntry(VarOffset(offset), ReadOnly)); | |
439 | } | |
440 | ||
441 | emitOpcode(op_put_to_scope); | |
442 | instructions().append(m_lexicalEnvironmentRegister->index()); | |
443 | instructions().append(addConstant(functionNode->ident())); | |
444 | instructions().append(m_calleeRegister.index()); | |
445 | instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); | |
446 | instructions().append(0); | |
447 | instructions().append(offset.offset()); | |
448 | } else { | |
449 | m_symbolTable->add( | |
450 | functionNode->ident().impl(), | |
451 | SymbolTableEntry(VarOffset(m_calleeRegister.virtualRegister()), ReadOnly)); | |
452 | } | |
14957cd0 | 453 | } |
81345200 | 454 | |
ed1e77d3 A |
455 | // This is our final act of weirdness. "arguments" is overridden by everything except the |
456 | // callee. We add it to the symbol table if it's not already there and it's not an argument. | |
457 | if (needsArguments) { | |
458 | // If "arguments" is overridden by a function or destructuring parameter name, then it's | |
459 | // OK for us to call createVariable() because it won't change anything. It's also OK for | |
460 | // us to them tell BytecodeGenerator::generate() to write to it because it will do so | |
461 | // before it initializes functions and destructuring parameters. But if "arguments" is | |
462 | // overridden by a "simple" function parameter, then we have to bail: createVariable() | |
463 | // would assert and BytecodeGenerator::generate() would write the "arguments" after the | |
464 | // argument value had already been properly initialized. | |
465 | ||
466 | bool haveParameterNamedArguments = false; | |
467 | for (unsigned i = 0; i < parameters.size(); ++i) { | |
468 | UniquedStringImpl* name = visibleNameForParameter(parameters.at(i)); | |
469 | if (name == propertyNames().arguments.impl()) { | |
470 | haveParameterNamedArguments = true; | |
471 | break; | |
472 | } | |
81345200 | 473 | } |
ed1e77d3 A |
474 | |
475 | if (!haveParameterNamedArguments) { | |
476 | createVariable( | |
477 | propertyNames().arguments, varKind(propertyNames().arguments.impl()), IsVariable); | |
478 | m_needToInitializeArguments = true; | |
93a37866 | 479 | } |
93a37866 | 480 | } |
ed1e77d3 | 481 | |
93a37866 | 482 | if (isConstructor()) { |
ed1e77d3 A |
483 | if (constructorKind() == ConstructorKind::Derived) { |
484 | m_newTargetRegister = addVar(); | |
485 | emitMove(m_newTargetRegister, &m_thisRegister); | |
486 | emitMoveEmptyValue(&m_thisRegister); | |
487 | } else | |
488 | emitCreateThis(&m_thisRegister); | |
489 | } else if (constructorKind() != ConstructorKind::None) { | |
490 | emitThrowTypeError("Cannot call a class constructor"); | |
491 | } else if (functionNode->usesThis() || codeBlock->usesEval()) { | |
81345200 A |
492 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); |
493 | emitOpcode(op_to_this); | |
93a37866 | 494 | instructions().append(kill(&m_thisRegister)); |
81345200 | 495 | instructions().append(0); |
ed1e77d3 | 496 | instructions().append(0); |
14957cd0 | 497 | } |
9dae56ea A |
498 | } |
499 | ||
81345200 A |
500 | BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) |
501 | : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) | |
502 | , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) | |
93a37866 | 503 | , m_symbolTable(codeBlock->symbolTable()) |
9dae56ea | 504 | , m_scopeNode(evalNode) |
93a37866 | 505 | , m_codeBlock(vm, codeBlock) |
6fe7ccc8 | 506 | , m_thisRegister(CallFrame::thisArgumentOffset()) |
9dae56ea | 507 | , m_codeType(EvalCode) |
93a37866 | 508 | , m_vm(&vm) |
9dae56ea | 509 | { |
ed1e77d3 A |
510 | for (auto& constantRegister : m_linkTimeConstantRegisters) |
511 | constantRegister = nullptr; | |
512 | ||
93a37866 | 513 | m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); |
6fe7ccc8 | 514 | m_codeBlock->setNumParameters(1); |
9dae56ea | 515 | |
93a37866 A |
516 | emitOpcode(op_enter); |
517 | ||
ed1e77d3 A |
518 | allocateAndEmitScope(); |
519 | ||
f9bf01c6 A |
520 | const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); |
521 | for (size_t i = 0; i < functionStack.size(); ++i) | |
93a37866 | 522 | m_codeBlock->addFunctionDecl(makeFunction(functionStack[i])); |
f9bf01c6 A |
523 | |
524 | const DeclarationStacks::VarStack& varStack = evalNode->varStack(); | |
525 | unsigned numVariables = varStack.size(); | |
93a37866 | 526 | Vector<Identifier, 0, UnsafeVectorOverflow> variables; |
f9bf01c6 | 527 | variables.reserveCapacity(numVariables); |
81345200 | 528 | for (size_t i = 0; i < numVariables; ++i) { |
ed1e77d3 | 529 | ASSERT(varStack[i].first.impl()->isAtomic() || varStack[i].first.impl()->isSymbol()); |
81345200 A |
530 | variables.append(varStack[i].first); |
531 | } | |
f9bf01c6 | 532 | codeBlock->adoptVariables(variables); |
9dae56ea A |
533 | } |
534 | ||
6fe7ccc8 A |
535 | BytecodeGenerator::~BytecodeGenerator() |
536 | { | |
6fe7ccc8 A |
537 | } |
538 | ||
ed1e77d3 | 539 | RegisterID* BytecodeGenerator::initializeNextParameter() |
93a37866 | 540 | { |
ed1e77d3 A |
541 | VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters()); |
542 | RegisterID& parameter = registerFor(reg); | |
543 | parameter.setIndex(reg.offset()); | |
93a37866 | 544 | m_codeBlock->addParameter(); |
ed1e77d3 | 545 | return ¶meter; |
6fe7ccc8 A |
546 | } |
547 | ||
ed1e77d3 | 548 | UniquedStringImpl* BytecodeGenerator::visibleNameForParameter(DestructuringPatternNode* pattern) |
14957cd0 | 549 | { |
ed1e77d3 A |
550 | if (pattern->isBindingNode()) { |
551 | const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty(); | |
552 | if (!m_functions.contains(ident.impl())) | |
553 | return ident.impl(); | |
554 | } | |
555 | return nullptr; | |
14957cd0 A |
556 | } |
557 | ||
9dae56ea A |
558 | RegisterID* BytecodeGenerator::newRegister() |
559 | { | |
81345200 A |
560 | m_calleeRegisters.append(virtualRegisterForLocal(m_calleeRegisters.size())); |
561 | int numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size()); | |
562 | numCalleeRegisters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeRegisters); | |
563 | m_codeBlock->m_numCalleeRegisters = numCalleeRegisters; | |
9dae56ea A |
564 | return &m_calleeRegisters.last(); |
565 | } | |
566 | ||
567 | RegisterID* BytecodeGenerator::newTemporary() | |
568 | { | |
569 | // Reclaim free register IDs. | |
570 | while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount()) | |
571 | m_calleeRegisters.removeLast(); | |
572 | ||
573 | RegisterID* result = newRegister(); | |
574 | result->setTemporary(); | |
575 | return result; | |
576 | } | |
577 | ||
93a37866 | 578 | LabelScopePtr BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) |
9dae56ea A |
579 | { |
580 | // Reclaim free label scopes. | |
581 | while (m_labelScopes.size() && !m_labelScopes.last().refCount()) | |
582 | m_labelScopes.removeLast(); | |
583 | ||
584 | // Allocate new label scope. | |
f9bf01c6 | 585 | LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets. |
9dae56ea | 586 | m_labelScopes.append(scope); |
81345200 | 587 | return LabelScopePtr(m_labelScopes, m_labelScopes.size() - 1); |
9dae56ea A |
588 | } |
589 | ||
590 | PassRefPtr<Label> BytecodeGenerator::newLabel() | |
591 | { | |
592 | // Reclaim free label IDs. | |
593 | while (m_labels.size() && !m_labels.last().refCount()) | |
594 | m_labels.removeLast(); | |
595 | ||
596 | // Allocate new label ID. | |
ed1e77d3 | 597 | m_labels.append(*this); |
9dae56ea A |
598 | return &m_labels.last(); |
599 | } | |
600 | ||
601 | PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* l0) | |
602 | { | |
603 | unsigned newLabelIndex = instructions().size(); | |
604 | l0->setLocation(newLabelIndex); | |
605 | ||
606 | if (m_codeBlock->numberOfJumpTargets()) { | |
607 | unsigned lastLabelIndex = m_codeBlock->lastJumpTarget(); | |
608 | ASSERT(lastLabelIndex <= newLabelIndex); | |
609 | if (newLabelIndex == lastLabelIndex) { | |
610 | // Peephole optimizations have already been disabled by emitting the last label | |
611 | return l0; | |
612 | } | |
613 | } | |
614 | ||
615 | m_codeBlock->addJumpTarget(newLabelIndex); | |
616 | ||
617 | // This disables peephole optimizations when an instruction is a jump target | |
618 | m_lastOpcodeID = op_end; | |
619 | return l0; | |
620 | } | |
621 | ||
622 | void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) | |
623 | { | |
14957cd0 A |
624 | #ifndef NDEBUG |
625 | size_t opcodePosition = instructions().size(); | |
626 | ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end); | |
627 | m_lastOpcodePosition = opcodePosition; | |
628 | #endif | |
93a37866 | 629 | instructions().append(opcodeID); |
9dae56ea A |
630 | m_lastOpcodeID = opcodeID; |
631 | } | |
632 | ||
93a37866 | 633 | UnlinkedArrayProfile BytecodeGenerator::newArrayProfile() |
6fe7ccc8 | 634 | { |
93a37866 | 635 | return m_codeBlock->addArrayProfile(); |
93a37866 A |
636 | } |
637 | ||
638 | UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile() | |
639 | { | |
93a37866 | 640 | return m_codeBlock->addArrayAllocationProfile(); |
93a37866 A |
641 | } |
642 | ||
643 | UnlinkedObjectAllocationProfile BytecodeGenerator::newObjectAllocationProfile() | |
644 | { | |
645 | return m_codeBlock->addObjectAllocationProfile(); | |
646 | } | |
647 | ||
648 | UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) | |
649 | { | |
93a37866 | 650 | UnlinkedValueProfile result = m_codeBlock->addValueProfile(); |
6fe7ccc8 A |
651 | emitOpcode(opcodeID); |
652 | return result; | |
653 | } | |
654 | ||
655 | void BytecodeGenerator::emitLoopHint() | |
656 | { | |
6fe7ccc8 | 657 | emitOpcode(op_loop_hint); |
6fe7ccc8 A |
658 | } |
659 | ||
9dae56ea A |
660 | void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index) |
661 | { | |
662 | ASSERT(instructions().size() >= 4); | |
663 | size_t size = instructions().size(); | |
664 | dstIndex = instructions().at(size - 3).u.operand; | |
665 | src1Index = instructions().at(size - 2).u.operand; | |
666 | src2Index = instructions().at(size - 1).u.operand; | |
667 | } | |
668 | ||
669 | void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex) | |
670 | { | |
671 | ASSERT(instructions().size() >= 3); | |
672 | size_t size = instructions().size(); | |
673 | dstIndex = instructions().at(size - 2).u.operand; | |
674 | srcIndex = instructions().at(size - 1).u.operand; | |
675 | } | |
676 | ||
677 | void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp() | |
678 | { | |
679 | ASSERT(instructions().size() >= 4); | |
680 | instructions().shrink(instructions().size() - 4); | |
14957cd0 | 681 | m_lastOpcodeID = op_end; |
9dae56ea A |
682 | } |
683 | ||
684 | void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp() | |
685 | { | |
686 | ASSERT(instructions().size() >= 3); | |
687 | instructions().shrink(instructions().size() - 3); | |
14957cd0 | 688 | m_lastOpcodeID = op_end; |
9dae56ea A |
689 | } |
690 | ||
691 | PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target) | |
692 | { | |
f9bf01c6 | 693 | size_t begin = instructions().size(); |
93a37866 | 694 | emitOpcode(op_jmp); |
f9bf01c6 | 695 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
696 | return target; |
697 | } | |
698 | ||
699 | PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target) | |
700 | { | |
f9bf01c6 | 701 | if (m_lastOpcodeID == op_less) { |
9dae56ea A |
702 | int dstIndex; |
703 | int src1Index; | |
704 | int src2Index; | |
705 | ||
706 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
707 | ||
708 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
709 | rewindBinaryOp(); | |
f9bf01c6 A |
710 | |
711 | size_t begin = instructions().size(); | |
93a37866 | 712 | emitOpcode(op_jless); |
9dae56ea A |
713 | instructions().append(src1Index); |
714 | instructions().append(src2Index); | |
f9bf01c6 | 715 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
716 | return target; |
717 | } | |
4e4e5a6f | 718 | } else if (m_lastOpcodeID == op_lesseq) { |
9dae56ea A |
719 | int dstIndex; |
720 | int src1Index; | |
721 | int src2Index; | |
722 | ||
723 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
724 | ||
725 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
726 | rewindBinaryOp(); | |
f9bf01c6 A |
727 | |
728 | size_t begin = instructions().size(); | |
93a37866 | 729 | emitOpcode(op_jlesseq); |
9dae56ea A |
730 | instructions().append(src1Index); |
731 | instructions().append(src2Index); | |
f9bf01c6 | 732 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
733 | return target; |
734 | } | |
6fe7ccc8 A |
735 | } else if (m_lastOpcodeID == op_greater) { |
736 | int dstIndex; | |
737 | int src1Index; | |
738 | int src2Index; | |
739 | ||
740 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
741 | ||
742 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
743 | rewindBinaryOp(); | |
744 | ||
745 | size_t begin = instructions().size(); | |
93a37866 | 746 | emitOpcode(op_jgreater); |
6fe7ccc8 A |
747 | instructions().append(src1Index); |
748 | instructions().append(src2Index); | |
749 | instructions().append(target->bind(begin, instructions().size())); | |
750 | return target; | |
751 | } | |
752 | } else if (m_lastOpcodeID == op_greatereq) { | |
753 | int dstIndex; | |
754 | int src1Index; | |
755 | int src2Index; | |
756 | ||
757 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
758 | ||
759 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
760 | rewindBinaryOp(); | |
761 | ||
762 | size_t begin = instructions().size(); | |
93a37866 | 763 | emitOpcode(op_jgreatereq); |
6fe7ccc8 A |
764 | instructions().append(src1Index); |
765 | instructions().append(src2Index); | |
766 | instructions().append(target->bind(begin, instructions().size())); | |
767 | return target; | |
768 | } | |
9dae56ea A |
769 | } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { |
770 | int dstIndex; | |
771 | int srcIndex; | |
772 | ||
773 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
774 | ||
775 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
776 | rewindUnaryOp(); | |
f9bf01c6 A |
777 | |
778 | size_t begin = instructions().size(); | |
9dae56ea A |
779 | emitOpcode(op_jeq_null); |
780 | instructions().append(srcIndex); | |
f9bf01c6 | 781 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
782 | return target; |
783 | } | |
784 | } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { | |
785 | int dstIndex; | |
786 | int srcIndex; | |
787 | ||
788 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
789 | ||
790 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
791 | rewindUnaryOp(); | |
f9bf01c6 A |
792 | |
793 | size_t begin = instructions().size(); | |
9dae56ea A |
794 | emitOpcode(op_jneq_null); |
795 | instructions().append(srcIndex); | |
f9bf01c6 | 796 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
797 | return target; |
798 | } | |
799 | } | |
800 | ||
f9bf01c6 A |
801 | size_t begin = instructions().size(); |
802 | ||
93a37866 | 803 | emitOpcode(op_jtrue); |
9dae56ea | 804 | instructions().append(cond->index()); |
f9bf01c6 | 805 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
806 | return target; |
807 | } | |
808 | ||
809 | PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target) | |
810 | { | |
f9bf01c6 | 811 | if (m_lastOpcodeID == op_less && target->isForward()) { |
9dae56ea A |
812 | int dstIndex; |
813 | int src1Index; | |
814 | int src2Index; | |
815 | ||
816 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
817 | ||
818 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
819 | rewindBinaryOp(); | |
f9bf01c6 A |
820 | |
821 | size_t begin = instructions().size(); | |
9dae56ea A |
822 | emitOpcode(op_jnless); |
823 | instructions().append(src1Index); | |
824 | instructions().append(src2Index); | |
f9bf01c6 | 825 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
826 | return target; |
827 | } | |
f9bf01c6 | 828 | } else if (m_lastOpcodeID == op_lesseq && target->isForward()) { |
ba379fdc A |
829 | int dstIndex; |
830 | int src1Index; | |
831 | int src2Index; | |
832 | ||
833 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
834 | ||
835 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
836 | rewindBinaryOp(); | |
f9bf01c6 A |
837 | |
838 | size_t begin = instructions().size(); | |
ba379fdc A |
839 | emitOpcode(op_jnlesseq); |
840 | instructions().append(src1Index); | |
841 | instructions().append(src2Index); | |
f9bf01c6 | 842 | instructions().append(target->bind(begin, instructions().size())); |
ba379fdc A |
843 | return target; |
844 | } | |
6fe7ccc8 A |
845 | } else if (m_lastOpcodeID == op_greater && target->isForward()) { |
846 | int dstIndex; | |
847 | int src1Index; | |
848 | int src2Index; | |
849 | ||
850 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
851 | ||
852 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
853 | rewindBinaryOp(); | |
854 | ||
855 | size_t begin = instructions().size(); | |
856 | emitOpcode(op_jngreater); | |
857 | instructions().append(src1Index); | |
858 | instructions().append(src2Index); | |
859 | instructions().append(target->bind(begin, instructions().size())); | |
860 | return target; | |
861 | } | |
862 | } else if (m_lastOpcodeID == op_greatereq && target->isForward()) { | |
863 | int dstIndex; | |
864 | int src1Index; | |
865 | int src2Index; | |
866 | ||
867 | retrieveLastBinaryOp(dstIndex, src1Index, src2Index); | |
868 | ||
869 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
870 | rewindBinaryOp(); | |
871 | ||
872 | size_t begin = instructions().size(); | |
873 | emitOpcode(op_jngreatereq); | |
874 | instructions().append(src1Index); | |
875 | instructions().append(src2Index); | |
876 | instructions().append(target->bind(begin, instructions().size())); | |
877 | return target; | |
878 | } | |
9dae56ea A |
879 | } else if (m_lastOpcodeID == op_not) { |
880 | int dstIndex; | |
881 | int srcIndex; | |
882 | ||
883 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
884 | ||
885 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
886 | rewindUnaryOp(); | |
f9bf01c6 A |
887 | |
888 | size_t begin = instructions().size(); | |
93a37866 | 889 | emitOpcode(op_jtrue); |
9dae56ea | 890 | instructions().append(srcIndex); |
f9bf01c6 | 891 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
892 | return target; |
893 | } | |
f9bf01c6 | 894 | } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { |
9dae56ea A |
895 | int dstIndex; |
896 | int srcIndex; | |
897 | ||
898 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
899 | ||
900 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
901 | rewindUnaryOp(); | |
f9bf01c6 A |
902 | |
903 | size_t begin = instructions().size(); | |
9dae56ea A |
904 | emitOpcode(op_jneq_null); |
905 | instructions().append(srcIndex); | |
f9bf01c6 | 906 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
907 | return target; |
908 | } | |
f9bf01c6 | 909 | } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { |
9dae56ea A |
910 | int dstIndex; |
911 | int srcIndex; | |
912 | ||
913 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
914 | ||
915 | if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { | |
916 | rewindUnaryOp(); | |
f9bf01c6 A |
917 | |
918 | size_t begin = instructions().size(); | |
9dae56ea A |
919 | emitOpcode(op_jeq_null); |
920 | instructions().append(srcIndex); | |
f9bf01c6 | 921 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
922 | return target; |
923 | } | |
924 | } | |
925 | ||
f9bf01c6 | 926 | size_t begin = instructions().size(); |
93a37866 | 927 | emitOpcode(op_jfalse); |
9dae56ea | 928 | instructions().append(cond->index()); |
f9bf01c6 | 929 | instructions().append(target->bind(begin, instructions().size())); |
9dae56ea A |
930 | return target; |
931 | } | |
932 | ||
ba379fdc A |
933 | PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target) |
934 | { | |
f9bf01c6 A |
935 | size_t begin = instructions().size(); |
936 | ||
ba379fdc A |
937 | emitOpcode(op_jneq_ptr); |
938 | instructions().append(cond->index()); | |
93a37866 | 939 | instructions().append(Special::CallFunction); |
f9bf01c6 | 940 | instructions().append(target->bind(begin, instructions().size())); |
ba379fdc A |
941 | return target; |
942 | } | |
943 | ||
944 | PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target) | |
945 | { | |
f9bf01c6 A |
946 | size_t begin = instructions().size(); |
947 | ||
ba379fdc A |
948 | emitOpcode(op_jneq_ptr); |
949 | instructions().append(cond->index()); | |
93a37866 | 950 | instructions().append(Special::ApplyFunction); |
f9bf01c6 | 951 | instructions().append(target->bind(begin, instructions().size())); |
ba379fdc A |
952 | return target; |
953 | } | |
954 | ||
ed1e77d3 A |
955 | bool BytecodeGenerator::hasConstant(const Identifier& ident) const |
956 | { | |
957 | UniquedStringImpl* rep = ident.impl(); | |
958 | return m_identifierMap.contains(rep); | |
959 | } | |
960 | ||
9dae56ea A |
961 | unsigned BytecodeGenerator::addConstant(const Identifier& ident) |
962 | { | |
ed1e77d3 | 963 | UniquedStringImpl* rep = ident.impl(); |
6fe7ccc8 A |
964 | IdentifierMap::AddResult result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers()); |
965 | if (result.isNewEntry) | |
81345200 | 966 | m_codeBlock->addIdentifier(ident); |
93a37866 A |
967 | |
968 | return result.iterator->value; | |
969 | } | |
970 | ||
971 | // We can't hash JSValue(), so we use a dedicated data member to cache it. | |
972 | RegisterID* BytecodeGenerator::addConstantEmptyValue() | |
973 | { | |
974 | if (!m_emptyValueRegister) { | |
975 | int index = m_nextConstantOffset; | |
976 | m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); | |
977 | ++m_nextConstantOffset; | |
978 | m_codeBlock->addConstant(JSValue()); | |
979 | m_emptyValueRegister = &m_constantPoolRegisters[index]; | |
980 | } | |
9dae56ea | 981 | |
93a37866 | 982 | return m_emptyValueRegister; |
9dae56ea A |
983 | } |
984 | ||
ed1e77d3 | 985 | RegisterID* BytecodeGenerator::addConstantValue(JSValue v, SourceCodeRepresentation sourceCodeRepresentation) |
9dae56ea | 986 | { |
93a37866 A |
987 | if (!v) |
988 | return addConstantEmptyValue(); | |
9dae56ea | 989 | |
93a37866 | 990 | int index = m_nextConstantOffset; |
ed1e77d3 A |
991 | |
992 | EncodedJSValueWithRepresentation valueMapKey { JSValue::encode(v), sourceCodeRepresentation }; | |
993 | JSValueMap::AddResult result = m_jsValueMap.add(valueMapKey, m_nextConstantOffset); | |
6fe7ccc8 | 994 | if (result.isNewEntry) { |
ba379fdc A |
995 | m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); |
996 | ++m_nextConstantOffset; | |
ed1e77d3 | 997 | m_codeBlock->addConstant(v, sourceCodeRepresentation); |
ba379fdc | 998 | } else |
93a37866 | 999 | index = result.iterator->value; |
ba379fdc | 1000 | return &m_constantPoolRegisters[index]; |
9dae56ea A |
1001 | } |
1002 | ||
ed1e77d3 A |
1003 | RegisterID* BytecodeGenerator::emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant type) |
1004 | { | |
1005 | unsigned constantIndex = static_cast<unsigned>(type); | |
1006 | if (!m_linkTimeConstantRegisters[constantIndex]) { | |
1007 | int index = m_nextConstantOffset; | |
1008 | m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); | |
1009 | ++m_nextConstantOffset; | |
1010 | m_codeBlock->addConstant(type); | |
1011 | m_linkTimeConstantRegisters[constantIndex] = &m_constantPoolRegisters[index]; | |
1012 | } | |
1013 | ||
1014 | emitOpcode(op_mov); | |
1015 | instructions().append(dst->index()); | |
1016 | instructions().append(m_linkTimeConstantRegisters[constantIndex]->index()); | |
1017 | ||
1018 | return dst; | |
1019 | } | |
1020 | ||
9dae56ea A |
1021 | unsigned BytecodeGenerator::addRegExp(RegExp* r) |
1022 | { | |
1023 | return m_codeBlock->addRegExp(r); | |
1024 | } | |
1025 | ||
ed1e77d3 | 1026 | RegisterID* BytecodeGenerator::emitMoveEmptyValue(RegisterID* dst) |
9dae56ea | 1027 | { |
ed1e77d3 | 1028 | RefPtr<RegisterID> emptyValue = addConstantEmptyValue(); |
93a37866 | 1029 | |
ed1e77d3 | 1030 | emitOpcode(op_mov); |
9dae56ea | 1031 | instructions().append(dst->index()); |
ed1e77d3 | 1032 | instructions().append(emptyValue->index()); |
9dae56ea A |
1033 | return dst; |
1034 | } | |
1035 | ||
81345200 A |
1036 | RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src) |
1037 | { | |
ed1e77d3 A |
1038 | ASSERT(src != m_emptyValueRegister); |
1039 | ||
1040 | m_staticPropertyAnalyzer.mov(dst->index(), src->index()); | |
1041 | emitOpcode(op_mov); | |
1042 | instructions().append(dst->index()); | |
1043 | instructions().append(src->index()); | |
1044 | ||
1045 | if (!dst->isTemporary() && vm()->typeProfiler()) | |
1046 | emitProfileType(dst, ProfileTypeBytecodeHasGlobalID, nullptr); | |
1047 | ||
1048 | return dst; | |
81345200 A |
1049 | } |
1050 | ||
9dae56ea A |
1051 | RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src) |
1052 | { | |
1053 | emitOpcode(opcodeID); | |
1054 | instructions().append(dst->index()); | |
1055 | instructions().append(src->index()); | |
1056 | return dst; | |
1057 | } | |
1058 | ||
93a37866 | 1059 | RegisterID* BytecodeGenerator::emitInc(RegisterID* srcDst) |
9dae56ea | 1060 | { |
93a37866 | 1061 | emitOpcode(op_inc); |
9dae56ea A |
1062 | instructions().append(srcDst->index()); |
1063 | return srcDst; | |
1064 | } | |
1065 | ||
93a37866 | 1066 | RegisterID* BytecodeGenerator::emitDec(RegisterID* srcDst) |
9dae56ea | 1067 | { |
93a37866 | 1068 | emitOpcode(op_dec); |
9dae56ea A |
1069 | instructions().append(srcDst->index()); |
1070 | return srcDst; | |
1071 | } | |
1072 | ||
9dae56ea A |
1073 | RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types) |
1074 | { | |
1075 | emitOpcode(opcodeID); | |
1076 | instructions().append(dst->index()); | |
1077 | instructions().append(src1->index()); | |
1078 | instructions().append(src2->index()); | |
1079 | ||
1080 | if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor || | |
ba379fdc | 1081 | opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div) |
9dae56ea | 1082 | instructions().append(types.toInt()); |
9dae56ea A |
1083 | |
1084 | return dst; | |
1085 | } | |
1086 | ||
1087 | RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2) | |
1088 | { | |
1089 | if (m_lastOpcodeID == op_typeof) { | |
1090 | int dstIndex; | |
1091 | int srcIndex; | |
1092 | ||
1093 | retrieveLastUnaryOp(dstIndex, srcIndex); | |
1094 | ||
1095 | if (src1->index() == dstIndex | |
1096 | && src1->isTemporary() | |
1097 | && m_codeBlock->isConstantRegisterIndex(src2->index()) | |
14957cd0 | 1098 | && m_codeBlock->constantRegister(src2->index()).get().isString()) { |
93a37866 | 1099 | const String& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue(); |
9dae56ea A |
1100 | if (value == "undefined") { |
1101 | rewindUnaryOp(); | |
1102 | emitOpcode(op_is_undefined); | |
1103 | instructions().append(dst->index()); | |
1104 | instructions().append(srcIndex); | |
1105 | return dst; | |
1106 | } | |
1107 | if (value == "boolean") { | |
1108 | rewindUnaryOp(); | |
1109 | emitOpcode(op_is_boolean); | |
1110 | instructions().append(dst->index()); | |
1111 | instructions().append(srcIndex); | |
1112 | return dst; | |
1113 | } | |
1114 | if (value == "number") { | |
1115 | rewindUnaryOp(); | |
1116 | emitOpcode(op_is_number); | |
1117 | instructions().append(dst->index()); | |
1118 | instructions().append(srcIndex); | |
1119 | return dst; | |
1120 | } | |
1121 | if (value == "string") { | |
1122 | rewindUnaryOp(); | |
1123 | emitOpcode(op_is_string); | |
1124 | instructions().append(dst->index()); | |
1125 | instructions().append(srcIndex); | |
1126 | return dst; | |
1127 | } | |
1128 | if (value == "object") { | |
1129 | rewindUnaryOp(); | |
ed1e77d3 | 1130 | emitOpcode(op_is_object_or_null); |
9dae56ea A |
1131 | instructions().append(dst->index()); |
1132 | instructions().append(srcIndex); | |
1133 | return dst; | |
1134 | } | |
1135 | if (value == "function") { | |
1136 | rewindUnaryOp(); | |
1137 | emitOpcode(op_is_function); | |
1138 | instructions().append(dst->index()); | |
1139 | instructions().append(srcIndex); | |
1140 | return dst; | |
1141 | } | |
1142 | } | |
1143 | } | |
1144 | ||
1145 | emitOpcode(opcodeID); | |
1146 | instructions().append(dst->index()); | |
1147 | instructions().append(src1->index()); | |
1148 | instructions().append(src2->index()); | |
1149 | return dst; | |
1150 | } | |
1151 | ||
ed1e77d3 | 1152 | void BytecodeGenerator::emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot) |
9dae56ea | 1153 | { |
ed1e77d3 A |
1154 | unsigned start = startDivot.offset; // Ranges are inclusive of their endpoints, AND 0 indexed. |
1155 | unsigned end = endDivot.offset - 1; // End Ranges already go one past the inclusive range, so subtract 1. | |
1156 | unsigned instructionOffset = instructions().size() - 1; | |
1157 | m_codeBlock->addTypeProfilerExpressionInfo(instructionOffset, start, end); | |
1158 | } | |
1159 | ||
1160 | void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag flag, const Identifier* identifier) | |
1161 | { | |
1162 | if (flag == ProfileTypeBytecodeGetFromScope || flag == ProfileTypeBytecodePutToScope) | |
1163 | RELEASE_ASSERT(identifier); | |
1164 | ||
1165 | // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType? | |
1166 | emitOpcode(op_profile_type); | |
1167 | instructions().append(registerToProfile->index()); | |
1168 | instructions().append(0); | |
1169 | instructions().append(flag); | |
1170 | instructions().append(identifier ? addConstant(*identifier) : 0); | |
1171 | instructions().append(resolveType()); | |
9dae56ea A |
1172 | } |
1173 | ||
ed1e77d3 | 1174 | void BytecodeGenerator::emitProfileControlFlow(int textOffset) |
9dae56ea | 1175 | { |
ed1e77d3 A |
1176 | if (vm()->controlFlowProfiler()) { |
1177 | RELEASE_ASSERT(textOffset >= 0); | |
1178 | size_t bytecodeOffset = instructions().size(); | |
1179 | m_codeBlock->addOpProfileControlFlowBytecodeOffset(bytecodeOffset); | |
1180 | ||
1181 | emitOpcode(op_profile_control_flow); | |
1182 | instructions().append(textOffset); | |
1183 | } | |
1184 | } | |
1185 | ||
1186 | RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b) | |
1187 | { | |
1188 | return emitLoad(dst, jsBoolean(b)); | |
9dae56ea A |
1189 | } |
1190 | ||
1191 | RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier) | |
1192 | { | |
81345200 | 1193 | JSString*& stringInMap = m_stringMap.add(identifier.impl(), nullptr).iterator->value; |
9dae56ea | 1194 | if (!stringInMap) |
93a37866 | 1195 | stringInMap = jsOwnedString(vm(), identifier.string()); |
ba379fdc | 1196 | return emitLoad(dst, JSValue(stringInMap)); |
9dae56ea A |
1197 | } |
1198 | ||
ed1e77d3 | 1199 | RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v, SourceCodeRepresentation sourceCodeRepresentation) |
9dae56ea | 1200 | { |
ed1e77d3 | 1201 | RegisterID* constantID = addConstantValue(v, sourceCodeRepresentation); |
9dae56ea A |
1202 | if (dst) |
1203 | return emitMove(dst, constantID); | |
1204 | return constantID; | |
1205 | } | |
1206 | ||
93a37866 | 1207 | RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst) |
9dae56ea | 1208 | { |
93a37866 A |
1209 | if (!m_globalObjectRegister) { |
1210 | int index = m_nextConstantOffset; | |
1211 | m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); | |
1212 | ++m_nextConstantOffset; | |
1213 | m_codeBlock->addConstant(JSValue()); | |
1214 | m_globalObjectRegister = &m_constantPoolRegisters[index]; | |
81345200 | 1215 | m_codeBlock->setGlobalObjectRegister(VirtualRegister(index)); |
93a37866 A |
1216 | } |
1217 | if (dst) | |
1218 | emitMove(dst, m_globalObjectRegister); | |
1219 | return m_globalObjectRegister; | |
1220 | } | |
1221 | ||
ed1e77d3 | 1222 | Variable BytecodeGenerator::variable(const Identifier& property) |
81345200 | 1223 | { |
ed1e77d3 A |
1224 | if (property == propertyNames().thisIdentifier) { |
1225 | return Variable( | |
1226 | property, VarOffset(thisRegister()->virtualRegister()), thisRegister(), | |
1227 | ReadOnly, Variable::SpecialVariable); | |
1228 | } | |
81345200 | 1229 | |
81345200 | 1230 | if (!shouldOptimizeLocals()) |
ed1e77d3 A |
1231 | return Variable(property); |
1232 | ||
1233 | SymbolTableEntry entry = symbolTable().get(property.impl()); | |
1234 | if (entry.isNull()) | |
1235 | return Variable(property); | |
1236 | ||
1237 | if (entry.varOffset().isScope() && m_localScopeDepth) { | |
1238 | // FIXME: We should be able to statically resolve through our local scopes. | |
1239 | // https://bugs.webkit.org/show_bug.cgi?id=141885 | |
1240 | return Variable(property); | |
1241 | } | |
1242 | ||
1243 | return variableForLocalEntry(property, entry); | |
1244 | } | |
93a37866 | 1245 | |
ed1e77d3 A |
1246 | Variable BytecodeGenerator::variablePerSymbolTable(const Identifier& property) |
1247 | { | |
81345200 A |
1248 | SymbolTableEntry entry = symbolTable().get(property.impl()); |
1249 | if (entry.isNull()) | |
ed1e77d3 A |
1250 | return Variable(property); |
1251 | ||
1252 | return variableForLocalEntry(property, entry); | |
1253 | } | |
81345200 | 1254 | |
ed1e77d3 A |
1255 | Variable BytecodeGenerator::variableForLocalEntry( |
1256 | const Identifier& property, const SymbolTableEntry& entry) | |
1257 | { | |
1258 | VarOffset offset = entry.varOffset(); | |
1259 | ||
1260 | RegisterID* local; | |
1261 | if (offset.isStack()) | |
1262 | local = ®isterFor(offset.stackOffset()); | |
1263 | else | |
1264 | local = nullptr; | |
1265 | ||
1266 | return Variable(property, offset, local, entry.getAttributes(), Variable::NormalVariable); | |
9dae56ea A |
1267 | } |
1268 | ||
ed1e77d3 A |
1269 | void BytecodeGenerator::createVariable( |
1270 | const Identifier& property, VarKind varKind, ConstantMode constantMode, | |
1271 | ExistingVariableMode existingVariableMode) | |
93a37866 | 1272 | { |
ed1e77d3 A |
1273 | ASSERT(property != propertyNames().thisIdentifier); |
1274 | ||
1275 | ConcurrentJITLocker locker(symbolTable().m_lock); | |
1276 | SymbolTableEntry entry = symbolTable().get(locker, property.impl()); | |
1277 | ||
1278 | if (!entry.isNull()) { | |
1279 | if (existingVariableMode == IgnoreExisting) | |
1280 | return; | |
1281 | ||
1282 | // Do some checks to ensure that the variable we're being asked to create is sufficiently | |
1283 | // compatible with the one we have already created. | |
81345200 | 1284 | |
ed1e77d3 A |
1285 | VarOffset offset = entry.varOffset(); |
1286 | ||
1287 | // We can't change our minds about whether it's captured. | |
1288 | if (offset.kind() != varKind || constantMode != entry.constantMode()) { | |
1289 | dataLog( | |
1290 | "Trying to add variable called ", property, " as ", varKind, "/", constantMode, | |
1291 | " but it was already added as ", offset, "/", entry.constantMode(), ".\n"); | |
1292 | RELEASE_ASSERT_NOT_REACHED(); | |
1293 | } | |
93a37866 | 1294 | |
ed1e77d3 A |
1295 | return; |
1296 | } | |
1297 | ||
1298 | VarOffset varOffset; | |
1299 | if (varKind == VarKind::Scope) | |
1300 | varOffset = VarOffset(symbolTable().takeNextScopeOffset(locker)); | |
1301 | else { | |
1302 | ASSERT(varKind == VarKind::Stack); | |
1303 | varOffset = VarOffset(virtualRegisterForLocal(m_calleeRegisters.size())); | |
1304 | } | |
1305 | SymbolTableEntry newEntry(varOffset, constantMode == IsConstant ? ReadOnly : 0); | |
1306 | symbolTable().add(locker, property.impl(), newEntry); | |
1307 | ||
1308 | if (varKind == VarKind::Stack) { | |
1309 | RegisterID* local = addVar(); | |
1310 | RELEASE_ASSERT(local->index() == varOffset.stackOffset().offset()); | |
1311 | } | |
93a37866 A |
1312 | } |
1313 | ||
1314 | void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target) | |
1315 | { | |
1316 | size_t begin = instructions().size(); | |
14957cd0 | 1317 | emitOpcode(op_check_has_instance); |
93a37866 A |
1318 | instructions().append(dst->index()); |
1319 | instructions().append(value->index()); | |
14957cd0 | 1320 | instructions().append(base->index()); |
93a37866 | 1321 | instructions().append(target->bind(begin, instructions().size())); |
14957cd0 A |
1322 | } |
1323 | ||
81345200 A |
1324 | // Indicates the least upper bound of resolve type based on local scope. The bytecode linker |
1325 | // will start with this ResolveType and compute the least upper bound including intercepting scopes. | |
1326 | ResolveType BytecodeGenerator::resolveType() | |
14957cd0 | 1327 | { |
81345200 A |
1328 | if (m_localScopeDepth) |
1329 | return Dynamic; | |
1330 | if (m_symbolTable && m_symbolTable->usesNonStrictEval()) | |
1331 | return GlobalPropertyWithVarInjectionChecks; | |
1332 | return GlobalProperty; | |
14957cd0 A |
1333 | } |
1334 | ||
ed1e77d3 | 1335 | RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Variable& variable) |
9dae56ea | 1336 | { |
ed1e77d3 A |
1337 | switch (variable.offset().kind()) { |
1338 | case VarKind::Stack: | |
1339 | return nullptr; | |
1340 | ||
1341 | case VarKind::DirectArgument: | |
1342 | return argumentsRegister(); | |
1343 | ||
1344 | case VarKind::Scope: | |
1345 | // This always refers to the activation that *we* allocated, and not the current scope that code | |
1346 | // lives in. Note that this will change once we have proper support for block scoping. Once that | |
1347 | // changes, it will be correct for this code to return scopeRegister(). The only reason why we | |
1348 | // don't do that already is that m_lexicalEnvironment is required by ConstDeclNode. ConstDeclNode | |
1349 | // requires weird things because it is a shameful pile of nonsense, but block scoping would make | |
1350 | // that code sensible and obviate the need for us to do bad things. | |
1351 | return m_lexicalEnvironmentRegister; | |
1352 | ||
1353 | case VarKind::Invalid: | |
1354 | // Indicates non-local resolution. | |
1355 | ||
1356 | ASSERT(!m_symbolTable || !m_symbolTable->contains(variable.ident().impl()) || resolveType() == Dynamic); | |
1357 | ||
1358 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); | |
1359 | ||
1360 | // resolve_scope dst, id, ResolveType, depth | |
1361 | emitOpcode(op_resolve_scope); | |
1362 | dst = tempDestination(dst); | |
1363 | instructions().append(kill(dst)); | |
1364 | instructions().append(scopeRegister()->index()); | |
1365 | instructions().append(addConstant(variable.ident())); | |
1366 | instructions().append(resolveType()); | |
1367 | instructions().append(0); | |
1368 | instructions().append(0); | |
1369 | return dst; | |
1370 | } | |
1371 | ||
1372 | RELEASE_ASSERT_NOT_REACHED(); | |
1373 | return nullptr; | |
9dae56ea A |
1374 | } |
1375 | ||
ed1e77d3 | 1376 | RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable& variable, ResolveMode resolveMode) |
9dae56ea | 1377 | { |
ed1e77d3 A |
1378 | switch (variable.offset().kind()) { |
1379 | case VarKind::Stack: | |
1380 | return emitMove(dst, variable.local()); | |
1381 | ||
1382 | case VarKind::DirectArgument: { | |
1383 | UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_arguments); | |
1384 | instructions().append(kill(dst)); | |
1385 | instructions().append(scope->index()); | |
1386 | instructions().append(variable.offset().capturedArgumentsOffset().offset()); | |
1387 | instructions().append(profile); | |
1388 | return dst; | |
1389 | } | |
1390 | ||
1391 | case VarKind::Scope: | |
1392 | case VarKind::Invalid: { | |
1393 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); | |
1394 | ||
1395 | // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand | |
1396 | UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_scope); | |
1397 | instructions().append(kill(dst)); | |
1398 | instructions().append(scope->index()); | |
1399 | instructions().append(addConstant(variable.ident())); | |
1400 | instructions().append(ResolveModeAndType(resolveMode, variable.offset().isScope() ? LocalClosureVar : resolveType()).operand()); | |
1401 | instructions().append(0); | |
1402 | instructions().append(variable.offset().isScope() ? variable.offset().scopeOffset().offset() : 0); | |
1403 | instructions().append(profile); | |
1404 | return dst; | |
1405 | } } | |
1406 | ||
1407 | RELEASE_ASSERT_NOT_REACHED(); | |
1408 | } | |
9dae56ea | 1409 | |
ed1e77d3 A |
1410 | RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable& variable, RegisterID* value, ResolveMode resolveMode) |
1411 | { | |
1412 | switch (variable.offset().kind()) { | |
1413 | case VarKind::Stack: | |
1414 | emitMove(variable.local(), value); | |
1415 | return value; | |
1416 | ||
1417 | case VarKind::DirectArgument: | |
1418 | emitOpcode(op_put_to_arguments); | |
1419 | instructions().append(scope->index()); | |
1420 | instructions().append(variable.offset().capturedArgumentsOffset().offset()); | |
1421 | instructions().append(value->index()); | |
1422 | return value; | |
1423 | ||
1424 | case VarKind::Scope: | |
1425 | case VarKind::Invalid: { | |
1426 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); | |
1427 | ||
1428 | // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand | |
1429 | emitOpcode(op_put_to_scope); | |
1430 | instructions().append(scope->index()); | |
1431 | instructions().append(addConstant(variable.ident())); | |
1432 | instructions().append(value->index()); | |
1433 | ScopeOffset offset; | |
1434 | if (variable.offset().isScope()) { | |
1435 | offset = variable.offset().scopeOffset(); | |
1436 | instructions().append(ResolveModeAndType(resolveMode, LocalClosureVar).operand()); | |
1437 | } else { | |
1438 | ASSERT(resolveType() != LocalClosureVar); | |
1439 | instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand()); | |
1440 | } | |
1441 | instructions().append(0); | |
1442 | instructions().append(!!offset ? offset.offset() : 0); | |
1443 | return value; | |
1444 | } } | |
1445 | ||
1446 | RELEASE_ASSERT_NOT_REACHED(); | |
9dae56ea A |
1447 | } |
1448 | ||
ed1e77d3 | 1449 | RegisterID* BytecodeGenerator::initializeVariable(const Variable& variable, RegisterID* value) |
9dae56ea | 1450 | { |
ed1e77d3 A |
1451 | RegisterID* scope; |
1452 | switch (variable.offset().kind()) { | |
1453 | case VarKind::Stack: | |
1454 | scope = nullptr; | |
1455 | break; | |
1456 | ||
1457 | case VarKind::DirectArgument: | |
1458 | scope = argumentsRegister(); | |
1459 | break; | |
1460 | ||
1461 | case VarKind::Scope: | |
1462 | scope = scopeRegister(); | |
1463 | break; | |
1464 | ||
1465 | default: | |
1466 | scope = nullptr; | |
1467 | RELEASE_ASSERT_NOT_REACHED(); | |
1468 | break; | |
1469 | } | |
9dae56ea | 1470 | |
ed1e77d3 | 1471 | return emitPutToScope(scope, variable, value, ThrowIfNotFound); |
14957cd0 A |
1472 | } |
1473 | ||
81345200 | 1474 | RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype) |
ed1e77d3 | 1475 | { |
81345200 A |
1476 | emitOpcode(op_instanceof); |
1477 | instructions().append(dst->index()); | |
1478 | instructions().append(value->index()); | |
1479 | instructions().append(basePrototype->index()); | |
1480 | return dst; | |
93a37866 A |
1481 | } |
1482 | ||
1483 | RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, RegisterID* value) | |
1484 | { | |
1485 | ASSERT(m_codeType == GlobalCode); | |
1486 | emitOpcode(op_init_global_const_nop); | |
ba379fdc | 1487 | instructions().append(0); |
93a37866 | 1488 | instructions().append(value->index()); |
ba379fdc | 1489 | instructions().append(0); |
93a37866 A |
1490 | instructions().append(addConstant(identifier)); |
1491 | return value; | |
9dae56ea A |
1492 | } |
1493 | ||
9dae56ea A |
1494 | RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property) |
1495 | { | |
9dae56ea | 1496 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); |
9dae56ea | 1497 | |
93a37866 A |
1498 | UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_id); |
1499 | instructions().append(kill(dst)); | |
9dae56ea A |
1500 | instructions().append(base->index()); |
1501 | instructions().append(addConstant(property)); | |
1502 | instructions().append(0); | |
1503 | instructions().append(0); | |
1504 | instructions().append(0); | |
1505 | instructions().append(0); | |
6fe7ccc8 | 1506 | instructions().append(profile); |
9dae56ea A |
1507 | return dst; |
1508 | } | |
1509 | ||
1510 | RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) | |
1511 | { | |
93a37866 A |
1512 | unsigned propertyIndex = addConstant(property); |
1513 | ||
1514 | m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); | |
1515 | ||
9dae56ea | 1516 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); |
9dae56ea A |
1517 | |
1518 | emitOpcode(op_put_by_id); | |
1519 | instructions().append(base->index()); | |
93a37866 | 1520 | instructions().append(propertyIndex); |
9dae56ea A |
1521 | instructions().append(value->index()); |
1522 | instructions().append(0); | |
1523 | instructions().append(0); | |
1524 | instructions().append(0); | |
1525 | instructions().append(0); | |
4e4e5a6f | 1526 | instructions().append(0); |
ed1e77d3 | 1527 | |
4e4e5a6f A |
1528 | return value; |
1529 | } | |
1530 | ||
ed1e77d3 | 1531 | RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType putType) |
4e4e5a6f | 1532 | { |
ed1e77d3 | 1533 | ASSERT(!parseIndex(property)); |
93a37866 A |
1534 | unsigned propertyIndex = addConstant(property); |
1535 | ||
1536 | m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); | |
1537 | ||
4e4e5a6f | 1538 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); |
4e4e5a6f A |
1539 | |
1540 | emitOpcode(op_put_by_id); | |
1541 | instructions().append(base->index()); | |
93a37866 | 1542 | instructions().append(propertyIndex); |
4e4e5a6f A |
1543 | instructions().append(value->index()); |
1544 | instructions().append(0); | |
1545 | instructions().append(0); | |
1546 | instructions().append(0); | |
1547 | instructions().append(0); | |
ed1e77d3 | 1548 | instructions().append(putType == PropertyNode::KnownDirect || property != m_vm->propertyNames->underscoreProto); |
9dae56ea A |
1549 | return value; |
1550 | } | |
1551 | ||
ed1e77d3 A |
1552 | void BytecodeGenerator::emitPutGetterById(RegisterID* base, const Identifier& property, RegisterID* getter) |
1553 | { | |
1554 | unsigned propertyIndex = addConstant(property); | |
1555 | m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); | |
1556 | ||
1557 | emitOpcode(op_put_getter_by_id); | |
1558 | instructions().append(base->index()); | |
1559 | instructions().append(propertyIndex); | |
1560 | instructions().append(getter->index()); | |
1561 | } | |
1562 | ||
1563 | void BytecodeGenerator::emitPutSetterById(RegisterID* base, const Identifier& property, RegisterID* setter) | |
1564 | { | |
1565 | unsigned propertyIndex = addConstant(property); | |
1566 | m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); | |
1567 | ||
1568 | emitOpcode(op_put_setter_by_id); | |
1569 | instructions().append(base->index()); | |
1570 | instructions().append(propertyIndex); | |
1571 | instructions().append(setter->index()); | |
1572 | } | |
1573 | ||
6fe7ccc8 | 1574 | void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter) |
9dae56ea | 1575 | { |
93a37866 A |
1576 | unsigned propertyIndex = addConstant(property); |
1577 | ||
1578 | m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); | |
1579 | ||
6fe7ccc8 | 1580 | emitOpcode(op_put_getter_setter); |
9dae56ea | 1581 | instructions().append(base->index()); |
93a37866 | 1582 | instructions().append(propertyIndex); |
6fe7ccc8 A |
1583 | instructions().append(getter->index()); |
1584 | instructions().append(setter->index()); | |
9dae56ea A |
1585 | } |
1586 | ||
1587 | RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property) | |
1588 | { | |
1589 | emitOpcode(op_del_by_id); | |
1590 | instructions().append(dst->index()); | |
1591 | instructions().append(base->index()); | |
1592 | instructions().append(addConstant(property)); | |
1593 | return dst; | |
1594 | } | |
1595 | ||
1596 | RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) | |
1597 | { | |
f9bf01c6 | 1598 | for (size_t i = m_forInContextStack.size(); i > 0; i--) { |
ed1e77d3 A |
1599 | ForInContext* context = m_forInContextStack[i - 1].get(); |
1600 | if (context->local() != property) | |
1601 | continue; | |
1602 | ||
1603 | if (!context->isValid()) | |
1604 | break; | |
1605 | ||
1606 | if (context->type() == ForInContext::IndexedForInContextType) { | |
1607 | property = static_cast<IndexedForInContext*>(context)->index(); | |
1608 | break; | |
f9bf01c6 | 1609 | } |
ed1e77d3 A |
1610 | |
1611 | ASSERT(context->type() == ForInContext::StructureForInContextType); | |
1612 | StructureForInContext* structureContext = static_cast<StructureForInContext*>(context); | |
1613 | UnlinkedValueProfile profile = emitProfiledOpcode(op_get_direct_pname); | |
1614 | instructions().append(kill(dst)); | |
1615 | instructions().append(base->index()); | |
1616 | instructions().append(property->index()); | |
1617 | instructions().append(structureContext->index()->index()); | |
1618 | instructions().append(structureContext->enumerator()->index()); | |
1619 | instructions().append(profile); | |
1620 | return dst; | |
f9bf01c6 | 1621 | } |
ed1e77d3 | 1622 | |
93a37866 A |
1623 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); |
1624 | UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_val); | |
1625 | instructions().append(kill(dst)); | |
9dae56ea A |
1626 | instructions().append(base->index()); |
1627 | instructions().append(property->index()); | |
93a37866 | 1628 | instructions().append(arrayProfile); |
6fe7ccc8 | 1629 | instructions().append(profile); |
9dae56ea A |
1630 | return dst; |
1631 | } | |
1632 | ||
1633 | RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) | |
1634 | { | |
93a37866 | 1635 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); |
ed1e77d3 | 1636 | emitOpcode(op_put_by_val); |
81345200 A |
1637 | instructions().append(base->index()); |
1638 | instructions().append(property->index()); | |
1639 | instructions().append(value->index()); | |
1640 | instructions().append(arrayProfile); | |
ed1e77d3 | 1641 | |
81345200 A |
1642 | return value; |
1643 | } | |
1644 | ||
1645 | RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) | |
1646 | { | |
1647 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); | |
1648 | emitOpcode(op_put_by_val_direct); | |
9dae56ea A |
1649 | instructions().append(base->index()); |
1650 | instructions().append(property->index()); | |
1651 | instructions().append(value->index()); | |
93a37866 | 1652 | instructions().append(arrayProfile); |
9dae56ea A |
1653 | return value; |
1654 | } | |
1655 | ||
1656 | RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property) | |
1657 | { | |
1658 | emitOpcode(op_del_by_val); | |
1659 | instructions().append(dst->index()); | |
1660 | instructions().append(base->index()); | |
1661 | instructions().append(property->index()); | |
1662 | return dst; | |
1663 | } | |
1664 | ||
1665 | RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value) | |
1666 | { | |
1667 | emitOpcode(op_put_by_index); | |
1668 | instructions().append(base->index()); | |
1669 | instructions().append(index); | |
1670 | instructions().append(value->index()); | |
1671 | return value; | |
1672 | } | |
1673 | ||
93a37866 | 1674 | RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst) |
ed1e77d3 | 1675 | { |
93a37866 A |
1676 | size_t begin = instructions().size(); |
1677 | m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3); | |
1678 | ||
ed1e77d3 | 1679 | m_codeBlock->addPropertyAccessInstruction(instructions().size()); |
93a37866 A |
1680 | emitOpcode(op_create_this); |
1681 | instructions().append(m_thisRegister.index()); | |
ed1e77d3 A |
1682 | instructions().append(m_thisRegister.index()); |
1683 | instructions().append(0); | |
93a37866 A |
1684 | instructions().append(0); |
1685 | return dst; | |
1686 | } | |
1687 | ||
ed1e77d3 A |
1688 | void BytecodeGenerator::emitTDZCheck(RegisterID* target) |
1689 | { | |
1690 | emitOpcode(op_check_tdz); | |
1691 | instructions().append(target->index()); | |
1692 | } | |
1693 | ||
9dae56ea A |
1694 | RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) |
1695 | { | |
93a37866 A |
1696 | size_t begin = instructions().size(); |
1697 | m_staticPropertyAnalyzer.newObject(dst->index(), begin + 2); | |
1698 | ||
9dae56ea A |
1699 | emitOpcode(op_new_object); |
1700 | instructions().append(dst->index()); | |
93a37866 A |
1701 | instructions().append(0); |
1702 | instructions().append(newObjectAllocationProfile()); | |
9dae56ea A |
1703 | return dst; |
1704 | } | |
1705 | ||
14957cd0 A |
1706 | unsigned BytecodeGenerator::addConstantBuffer(unsigned length) |
1707 | { | |
1708 | return m_codeBlock->addConstantBuffer(length); | |
1709 | } | |
1710 | ||
1711 | JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier) | |
1712 | { | |
81345200 | 1713 | JSString*& stringInMap = m_stringMap.add(identifier.impl(), nullptr).iterator->value; |
14957cd0 | 1714 | if (!stringInMap) { |
93a37866 | 1715 | stringInMap = jsString(vm(), identifier.string()); |
14957cd0 A |
1716 | addConstantValue(stringInMap); |
1717 | } | |
1718 | return stringInMap; | |
1719 | } | |
1720 | ||
ed1e77d3 A |
1721 | JSTemplateRegistryKey* BytecodeGenerator::addTemplateRegistryKeyConstant(const TemplateRegistryKey& templateRegistryKey) |
1722 | { | |
1723 | JSTemplateRegistryKey*& templateRegistryKeyInMap = m_templateRegistryKeyMap.add(templateRegistryKey, nullptr).iterator->value; | |
1724 | if (!templateRegistryKeyInMap) { | |
1725 | templateRegistryKeyInMap = JSTemplateRegistryKey::create(*vm(), templateRegistryKey); | |
1726 | addConstantValue(templateRegistryKeyInMap); | |
1727 | } | |
1728 | return templateRegistryKeyInMap; | |
1729 | } | |
1730 | ||
14957cd0 | 1731 | RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length) |
9dae56ea | 1732 | { |
14957cd0 A |
1733 | #if !ASSERT_DISABLED |
1734 | unsigned checkLength = 0; | |
1735 | #endif | |
1736 | bool hadVariableExpression = false; | |
1737 | if (length) { | |
1738 | for (ElementNode* n = elements; n; n = n->next()) { | |
93a37866 | 1739 | if (!n->value()->isConstant()) { |
14957cd0 A |
1740 | hadVariableExpression = true; |
1741 | break; | |
1742 | } | |
1743 | if (n->elision()) | |
1744 | break; | |
1745 | #if !ASSERT_DISABLED | |
1746 | checkLength++; | |
1747 | #endif | |
1748 | } | |
1749 | if (!hadVariableExpression) { | |
1750 | ASSERT(length == checkLength); | |
1751 | unsigned constantBufferIndex = addConstantBuffer(length); | |
93a37866 | 1752 | JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex).data(); |
14957cd0 A |
1753 | unsigned index = 0; |
1754 | for (ElementNode* n = elements; index < length; n = n->next()) { | |
93a37866 A |
1755 | ASSERT(n->value()->isConstant()); |
1756 | constantBuffer[index++] = static_cast<ConstantNode*>(n->value())->jsValue(*this); | |
14957cd0 A |
1757 | } |
1758 | emitOpcode(op_new_array_buffer); | |
1759 | instructions().append(dst->index()); | |
1760 | instructions().append(constantBufferIndex); | |
1761 | instructions().append(length); | |
93a37866 | 1762 | instructions().append(newArrayAllocationProfile()); |
14957cd0 A |
1763 | return dst; |
1764 | } | |
1765 | } | |
1766 | ||
93a37866 | 1767 | Vector<RefPtr<RegisterID>, 16, UnsafeVectorOverflow> argv; |
9dae56ea | 1768 | for (ElementNode* n = elements; n; n = n->next()) { |
81345200 | 1769 | if (!length) |
9dae56ea | 1770 | break; |
81345200 A |
1771 | length--; |
1772 | ASSERT(!n->value()->isSpreadExpression()); | |
9dae56ea A |
1773 | argv.append(newTemporary()); |
1774 | // op_new_array requires the initial values to be a sequential range of registers | |
81345200 | 1775 | ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() - 1); |
9dae56ea A |
1776 | emitNode(argv.last().get(), n->value()); |
1777 | } | |
81345200 | 1778 | ASSERT(!length); |
9dae56ea A |
1779 | emitOpcode(op_new_array); |
1780 | instructions().append(dst->index()); | |
1781 | instructions().append(argv.size() ? argv[0]->index() : 0); // argv | |
1782 | instructions().append(argv.size()); // argc | |
93a37866 | 1783 | instructions().append(newArrayAllocationProfile()); |
9dae56ea A |
1784 | return dst; |
1785 | } | |
1786 | ||
ed1e77d3 | 1787 | RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) |
14957cd0 | 1788 | { |
ed1e77d3 | 1789 | return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(function))); |
14957cd0 | 1790 | } |
f9bf01c6 | 1791 | |
ed1e77d3 | 1792 | RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index) |
14957cd0 | 1793 | { |
ed1e77d3 | 1794 | emitOpcode(op_new_func); |
9dae56ea | 1795 | instructions().append(dst->index()); |
ed1e77d3 | 1796 | instructions().append(scopeRegister()->index()); |
f9bf01c6 | 1797 | instructions().append(index); |
9dae56ea A |
1798 | return dst; |
1799 | } | |
1800 | ||
1801 | RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp) | |
1802 | { | |
1803 | emitOpcode(op_new_regexp); | |
1804 | instructions().append(dst->index()); | |
1805 | instructions().append(addRegExp(regExp)); | |
1806 | return dst; | |
1807 | } | |
1808 | ||
9dae56ea A |
1809 | RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n) |
1810 | { | |
f9bf01c6 | 1811 | FunctionBodyNode* function = n->body(); |
93a37866 | 1812 | unsigned index = m_codeBlock->addFunctionExpr(makeFunction(function)); |
ed1e77d3 | 1813 | |
9dae56ea A |
1814 | emitOpcode(op_new_func_exp); |
1815 | instructions().append(r0->index()); | |
ed1e77d3 | 1816 | instructions().append(scopeRegister()->index()); |
f9bf01c6 | 1817 | instructions().append(index); |
9dae56ea A |
1818 | return r0; |
1819 | } | |
1820 | ||
ed1e77d3 | 1821 | RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name) |
ba379fdc | 1822 | { |
ed1e77d3 | 1823 | UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name); |
14957cd0 | 1824 | |
ed1e77d3 | 1825 | unsigned index = m_codeBlock->addFunctionExpr(executable); |
14957cd0 | 1826 | |
ed1e77d3 A |
1827 | emitOpcode(op_new_func_exp); |
1828 | instructions().append(dst->index()); | |
1829 | instructions().append(scopeRegister()->index()); | |
1830 | instructions().append(index); | |
1831 | return dst; | |
ba379fdc A |
1832 | } |
1833 | ||
ed1e77d3 | 1834 | RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
9dae56ea | 1835 | { |
ed1e77d3 | 1836 | return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd); |
9dae56ea A |
1837 | } |
1838 | ||
81345200 | 1839 | RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
93a37866 | 1840 | { |
81345200 | 1841 | return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, divotStart, divotEnd); |
93a37866 A |
1842 | } |
1843 | ||
1844 | ExpectedFunction BytecodeGenerator::expectedFunctionForIdentifier(const Identifier& identifier) | |
1845 | { | |
ed1e77d3 | 1846 | if (identifier == m_vm->propertyNames->Object || identifier == m_vm->propertyNames->ObjectPrivateName) |
93a37866 | 1847 | return ExpectObjectConstructor; |
ed1e77d3 | 1848 | if (identifier == m_vm->propertyNames->Array || identifier == m_vm->propertyNames->ArrayPrivateName) |
93a37866 A |
1849 | return ExpectArrayConstructor; |
1850 | return NoExpectedFunction; | |
1851 | } | |
1852 | ||
1853 | ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, Label* done) | |
14957cd0 | 1854 | { |
93a37866 A |
1855 | RefPtr<Label> realCall = newLabel(); |
1856 | switch (expectedFunction) { | |
1857 | case ExpectObjectConstructor: { | |
1858 | // If the number of arguments is non-zero, then we can't do anything interesting. | |
1859 | if (callArguments.argumentCountIncludingThis() >= 2) | |
1860 | return NoExpectedFunction; | |
1861 | ||
1862 | size_t begin = instructions().size(); | |
1863 | emitOpcode(op_jneq_ptr); | |
1864 | instructions().append(func->index()); | |
1865 | instructions().append(Special::ObjectConstructor); | |
1866 | instructions().append(realCall->bind(begin, instructions().size())); | |
1867 | ||
1868 | if (dst != ignoredResult()) | |
1869 | emitNewObject(dst); | |
1870 | break; | |
1871 | } | |
1872 | ||
1873 | case ExpectArrayConstructor: { | |
1874 | // If you're doing anything other than "new Array()" or "new Array(foo)" then we | |
1875 | // don't do inline it, for now. The only reason is that call arguments are in | |
1876 | // the opposite order of what op_new_array expects, so we'd either need to change | |
1877 | // how op_new_array works or we'd need an op_new_array_reverse. Neither of these | |
1878 | // things sounds like it's worth it. | |
1879 | if (callArguments.argumentCountIncludingThis() > 2) | |
1880 | return NoExpectedFunction; | |
1881 | ||
1882 | size_t begin = instructions().size(); | |
1883 | emitOpcode(op_jneq_ptr); | |
1884 | instructions().append(func->index()); | |
1885 | instructions().append(Special::ArrayConstructor); | |
1886 | instructions().append(realCall->bind(begin, instructions().size())); | |
1887 | ||
1888 | if (dst != ignoredResult()) { | |
1889 | if (callArguments.argumentCountIncludingThis() == 2) { | |
1890 | emitOpcode(op_new_array_with_size); | |
1891 | instructions().append(dst->index()); | |
1892 | instructions().append(callArguments.argumentRegister(0)->index()); | |
1893 | instructions().append(newArrayAllocationProfile()); | |
1894 | } else { | |
1895 | ASSERT(callArguments.argumentCountIncludingThis() == 1); | |
1896 | emitOpcode(op_new_array); | |
1897 | instructions().append(dst->index()); | |
1898 | instructions().append(0); | |
1899 | instructions().append(0); | |
1900 | instructions().append(newArrayAllocationProfile()); | |
1901 | } | |
1902 | } | |
1903 | break; | |
1904 | } | |
1905 | ||
1906 | default: | |
1907 | ASSERT(expectedFunction == NoExpectedFunction); | |
1908 | return NoExpectedFunction; | |
1909 | } | |
1910 | ||
1911 | size_t begin = instructions().size(); | |
1912 | emitOpcode(op_jmp); | |
1913 | instructions().append(done->bind(begin, instructions().size())); | |
1914 | emitLabel(realCall.get()); | |
1915 | ||
1916 | return expectedFunction; | |
14957cd0 A |
1917 | } |
1918 | ||
81345200 | 1919 | RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
9dae56ea A |
1920 | { |
1921 | ASSERT(opcodeID == op_call || opcodeID == op_call_eval); | |
1922 | ASSERT(func->refCount()); | |
9dae56ea | 1923 | |
14957cd0 A |
1924 | if (m_shouldEmitProfileHooks) |
1925 | emitMove(callArguments.profileHookRegister(), func); | |
9dae56ea A |
1926 | |
1927 | // Generate code for arguments. | |
6fe7ccc8 | 1928 | unsigned argument = 0; |
81345200 A |
1929 | if (callArguments.argumentsNode()) { |
1930 | ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; | |
1931 | if (n && n->m_expr->isSpreadExpression()) { | |
1932 | RELEASE_ASSERT(!n->m_next); | |
1933 | auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression(); | |
1934 | RefPtr<RegisterID> argumentRegister; | |
ed1e77d3 | 1935 | argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); |
81345200 A |
1936 | RefPtr<RegisterID> thisRegister = emitMove(newTemporary(), callArguments.thisRegister()); |
1937 | return emitCallVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd); | |
1938 | } | |
1939 | for (; n; n = n->m_next) | |
1940 | emitNode(callArguments.argumentRegister(argument++), n); | |
1941 | } | |
1942 | ||
9dae56ea | 1943 | // Reserve space for call frame. |
93a37866 A |
1944 | Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame; |
1945 | for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i) | |
9dae56ea A |
1946 | callFrame.append(newTemporary()); |
1947 | ||
1948 | if (m_shouldEmitProfileHooks) { | |
1949 | emitOpcode(op_profile_will_call); | |
14957cd0 | 1950 | instructions().append(callArguments.profileHookRegister()->index()); |
9dae56ea A |
1951 | } |
1952 | ||
81345200 | 1953 | emitExpressionInfo(divot, divotStart, divotEnd); |
9dae56ea | 1954 | |
93a37866 A |
1955 | RefPtr<Label> done = newLabel(); |
1956 | expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get()); | |
1957 | ||
9dae56ea | 1958 | // Emit call. |
93a37866 | 1959 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); |
81345200 A |
1960 | UnlinkedValueProfile profile = emitProfiledOpcode(opcodeID); |
1961 | ASSERT(dst); | |
1962 | ASSERT(dst != ignoredResult()); | |
1963 | instructions().append(dst->index()); | |
1964 | instructions().append(func->index()); | |
1965 | instructions().append(callArguments.argumentCountIncludingThis()); | |
1966 | instructions().append(callArguments.stackOffset()); | |
6fe7ccc8 | 1967 | instructions().append(m_codeBlock->addLLIntCallLinkInfo()); |
6fe7ccc8 | 1968 | instructions().append(0); |
93a37866 | 1969 | instructions().append(arrayProfile); |
81345200 | 1970 | instructions().append(profile); |
93a37866 A |
1971 | |
1972 | if (expectedFunction != NoExpectedFunction) | |
1973 | emitLabel(done.get()); | |
9dae56ea A |
1974 | |
1975 | if (m_shouldEmitProfileHooks) { | |
1976 | emitOpcode(op_profile_did_call); | |
14957cd0 | 1977 | instructions().append(callArguments.profileHookRegister()->index()); |
9dae56ea A |
1978 | } |
1979 | ||
1980 | return dst; | |
1981 | } | |
1982 | ||
81345200 A |
1983 | RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
1984 | { | |
1985 | return emitCallVarargs(op_call_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd); | |
1986 | } | |
1987 | ||
ed1e77d3 | 1988 | RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
81345200 | 1989 | { |
ed1e77d3 | 1990 | return emitCallVarargs(op_construct_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd); |
81345200 A |
1991 | } |
1992 | ||
1993 | RegisterID* BytecodeGenerator::emitCallVarargs(OpcodeID opcode, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) | |
ba379fdc | 1994 | { |
ba379fdc | 1995 | if (m_shouldEmitProfileHooks) { |
6fe7ccc8 | 1996 | emitMove(profileHookRegister, func); |
ba379fdc | 1997 | emitOpcode(op_profile_will_call); |
6fe7ccc8 | 1998 | instructions().append(profileHookRegister->index()); |
ba379fdc A |
1999 | } |
2000 | ||
81345200 | 2001 | emitExpressionInfo(divot, divotStart, divotEnd); |
6fe7ccc8 | 2002 | |
ba379fdc | 2003 | // Emit call. |
81345200 A |
2004 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); |
2005 | UnlinkedValueProfile profile = emitProfiledOpcode(opcode); | |
2006 | ASSERT(dst != ignoredResult()); | |
2007 | instructions().append(dst->index()); | |
6fe7ccc8 | 2008 | instructions().append(func->index()); |
81345200 | 2009 | instructions().append(thisRegister ? thisRegister->index() : 0); |
6fe7ccc8 A |
2010 | instructions().append(arguments->index()); |
2011 | instructions().append(firstFreeRegister->index()); | |
81345200 A |
2012 | instructions().append(firstVarArgOffset); |
2013 | instructions().append(arrayProfile); | |
2014 | instructions().append(profile); | |
ba379fdc A |
2015 | if (m_shouldEmitProfileHooks) { |
2016 | emitOpcode(op_profile_did_call); | |
6fe7ccc8 | 2017 | instructions().append(profileHookRegister->index()); |
ba379fdc A |
2018 | } |
2019 | return dst; | |
2020 | } | |
2021 | ||
ed1e77d3 A |
2022 | void BytecodeGenerator::emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister, |
2023 | RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition& position) | |
9dae56ea | 2024 | { |
ed1e77d3 | 2025 | RefPtr<RegisterID> descriptorRegister = emitNewObject(newTemporary()); |
93a37866 | 2026 | |
ed1e77d3 A |
2027 | RefPtr<RegisterID> trueRegister = emitLoad(newTemporary(), true); |
2028 | if (options & PropertyConfigurable) | |
2029 | emitDirectPutById(descriptorRegister.get(), propertyNames().configurable, trueRegister.get(), PropertyNode::Unknown); | |
2030 | if (options & PropertyWritable) | |
2031 | emitDirectPutById(descriptorRegister.get(), propertyNames().writable, trueRegister.get(), PropertyNode::Unknown); | |
2032 | else if (valueRegister) { | |
2033 | RefPtr<RegisterID> falseRegister = emitLoad(newTemporary(), false); | |
2034 | emitDirectPutById(descriptorRegister.get(), propertyNames().writable, falseRegister.get(), PropertyNode::Unknown); | |
14957cd0 | 2035 | } |
ed1e77d3 A |
2036 | if (options & PropertyEnumerable) |
2037 | emitDirectPutById(descriptorRegister.get(), propertyNames().enumerable, trueRegister.get(), PropertyNode::Unknown); | |
2038 | ||
2039 | if (valueRegister) | |
2040 | emitDirectPutById(descriptorRegister.get(), propertyNames().value, valueRegister, PropertyNode::Unknown); | |
2041 | if (getterRegister) | |
2042 | emitDirectPutById(descriptorRegister.get(), propertyNames().get, getterRegister, PropertyNode::Unknown); | |
2043 | if (setterRegister) | |
2044 | emitDirectPutById(descriptorRegister.get(), propertyNames().set, setterRegister, PropertyNode::Unknown); | |
2045 | ||
2046 | RefPtr<RegisterID> definePropertyRegister = emitMoveLinkTimeConstant(newTemporary(), LinkTimeConstant::DefinePropertyFunction); | |
2047 | ||
2048 | CallArguments callArguments(*this, nullptr, 3); | |
2049 | emitLoad(callArguments.thisRegister(), jsUndefined()); | |
2050 | emitMove(callArguments.argumentRegister(0), newObj); | |
2051 | emitMove(callArguments.argumentRegister(1), propertyNameRegister); | |
2052 | emitMove(callArguments.argumentRegister(2), descriptorRegister.get()); | |
2053 | ||
2054 | emitCall(newTemporary(), definePropertyRegister.get(), NoExpectedFunction, callArguments, position, position, position); | |
2055 | } | |
2056 | ||
2057 | RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) | |
2058 | { | |
2059 | if (isConstructor()) { | |
2060 | bool derived = constructorKind() == ConstructorKind::Derived; | |
2061 | if (derived && src->index() == m_thisRegister.index()) | |
2062 | emitTDZCheck(src); | |
2063 | ||
2064 | RefPtr<Label> isObjectLabel = newLabel(); | |
2065 | emitJumpIfTrue(emitIsObject(newTemporary(), src), isObjectLabel.get()); | |
2066 | ||
2067 | if (derived) { | |
2068 | RefPtr<Label> isUndefinedLabel = newLabel(); | |
2069 | emitJumpIfTrue(emitIsUndefined(newTemporary(), src), isUndefinedLabel.get()); | |
2070 | emitThrowTypeError("Cannot return a non-object type in the constructor of a derived class."); | |
2071 | emitLabel(isUndefinedLabel.get()); | |
2072 | if (constructorKind() == ConstructorKind::Derived) | |
2073 | emitTDZCheck(&m_thisRegister); | |
2074 | } | |
9dae56ea | 2075 | |
ed1e77d3 A |
2076 | emitUnaryNoDstOp(op_ret, &m_thisRegister); |
2077 | ||
2078 | emitLabel(isObjectLabel.get()); | |
14957cd0 | 2079 | } |
ed1e77d3 | 2080 | |
9dae56ea A |
2081 | return emitUnaryNoDstOp(op_ret, src); |
2082 | } | |
2083 | ||
2084 | RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* src) | |
2085 | { | |
2086 | emitOpcode(opcodeID); | |
2087 | instructions().append(src->index()); | |
2088 | return src; | |
2089 | } | |
2090 | ||
81345200 | 2091 | RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
9dae56ea A |
2092 | { |
2093 | ASSERT(func->refCount()); | |
2094 | ||
14957cd0 A |
2095 | if (m_shouldEmitProfileHooks) |
2096 | emitMove(callArguments.profileHookRegister(), func); | |
9dae56ea A |
2097 | |
2098 | // Generate code for arguments. | |
6fe7ccc8 | 2099 | unsigned argument = 0; |
14957cd0 | 2100 | if (ArgumentsNode* argumentsNode = callArguments.argumentsNode()) { |
81345200 A |
2101 | |
2102 | ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; | |
2103 | if (n && n->m_expr->isSpreadExpression()) { | |
2104 | RELEASE_ASSERT(!n->m_next); | |
2105 | auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression(); | |
2106 | RefPtr<RegisterID> argumentRegister; | |
ed1e77d3 A |
2107 | argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); |
2108 | return emitConstructVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd); | |
81345200 A |
2109 | } |
2110 | ||
14957cd0 | 2111 | for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) |
6fe7ccc8 | 2112 | emitNode(callArguments.argumentRegister(argument++), n); |
9dae56ea A |
2113 | } |
2114 | ||
2115 | if (m_shouldEmitProfileHooks) { | |
2116 | emitOpcode(op_profile_will_call); | |
14957cd0 | 2117 | instructions().append(callArguments.profileHookRegister()->index()); |
9dae56ea A |
2118 | } |
2119 | ||
9dae56ea | 2120 | // Reserve space for call frame. |
93a37866 A |
2121 | Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame; |
2122 | for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i) | |
9dae56ea A |
2123 | callFrame.append(newTemporary()); |
2124 | ||
81345200 | 2125 | emitExpressionInfo(divot, divotStart, divotEnd); |
93a37866 A |
2126 | |
2127 | RefPtr<Label> done = newLabel(); | |
2128 | expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get()); | |
9dae56ea | 2129 | |
81345200 A |
2130 | UnlinkedValueProfile profile = emitProfiledOpcode(op_construct); |
2131 | ASSERT(dst != ignoredResult()); | |
2132 | instructions().append(dst->index()); | |
2133 | instructions().append(func->index()); | |
2134 | instructions().append(callArguments.argumentCountIncludingThis()); | |
2135 | instructions().append(callArguments.stackOffset()); | |
6fe7ccc8 | 2136 | instructions().append(m_codeBlock->addLLIntCallLinkInfo()); |
6fe7ccc8 | 2137 | instructions().append(0); |
6fe7ccc8 | 2138 | instructions().append(0); |
81345200 | 2139 | instructions().append(profile); |
9dae56ea | 2140 | |
93a37866 A |
2141 | if (expectedFunction != NoExpectedFunction) |
2142 | emitLabel(done.get()); | |
2143 | ||
9dae56ea A |
2144 | if (m_shouldEmitProfileHooks) { |
2145 | emitOpcode(op_profile_did_call); | |
14957cd0 | 2146 | instructions().append(callArguments.profileHookRegister()->index()); |
9dae56ea A |
2147 | } |
2148 | ||
2149 | return dst; | |
2150 | } | |
2151 | ||
ba379fdc A |
2152 | RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count) |
2153 | { | |
2154 | emitOpcode(op_strcat); | |
2155 | instructions().append(dst->index()); | |
2156 | instructions().append(src->index()); | |
2157 | instructions().append(count); | |
2158 | ||
2159 | return dst; | |
2160 | } | |
2161 | ||
2162 | void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src) | |
2163 | { | |
2164 | emitOpcode(op_to_primitive); | |
2165 | instructions().append(dst->index()); | |
2166 | instructions().append(src->index()); | |
2167 | } | |
2168 | ||
ed1e77d3 A |
2169 | void BytecodeGenerator::emitGetScope() |
2170 | { | |
2171 | emitOpcode(op_get_scope); | |
2172 | instructions().append(scopeRegister()->index()); | |
2173 | } | |
2174 | ||
2175 | RegisterID* BytecodeGenerator::emitPushWithScope(RegisterID* dst, RegisterID* scope) | |
9dae56ea | 2176 | { |
9dae56ea A |
2177 | ControlFlowContext context; |
2178 | context.isFinallyBlock = false; | |
2179 | m_scopeContextStack.append(context); | |
81345200 | 2180 | m_localScopeDepth++; |
9dae56ea | 2181 | |
ed1e77d3 | 2182 | return emitUnaryOp(op_push_with_scope, dst, scope); |
9dae56ea A |
2183 | } |
2184 | ||
ed1e77d3 | 2185 | void BytecodeGenerator::emitPopScope(RegisterID* srcDst) |
9dae56ea A |
2186 | { |
2187 | ASSERT(m_scopeContextStack.size()); | |
2188 | ASSERT(!m_scopeContextStack.last().isFinallyBlock); | |
2189 | ||
2190 | emitOpcode(op_pop_scope); | |
ed1e77d3 | 2191 | instructions().append(srcDst->index()); |
9dae56ea A |
2192 | |
2193 | m_scopeContextStack.removeLast(); | |
81345200 | 2194 | m_localScopeDepth--; |
9dae56ea A |
2195 | } |
2196 | ||
81345200 | 2197 | void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, unsigned line, unsigned charOffset, unsigned lineStart) |
9dae56ea | 2198 | { |
4e4e5a6f A |
2199 | #if ENABLE(DEBUG_WITH_BREAKPOINT) |
2200 | if (debugHookID != DidReachBreakpoint) | |
2201 | return; | |
2202 | #else | |
9dae56ea A |
2203 | if (!m_shouldEmitDebugHooks) |
2204 | return; | |
4e4e5a6f | 2205 | #endif |
81345200 A |
2206 | JSTextPosition divot(line, charOffset, lineStart); |
2207 | emitExpressionInfo(divot, divot, divot); | |
9dae56ea A |
2208 | emitOpcode(op_debug); |
2209 | instructions().append(debugHookID); | |
81345200 | 2210 | instructions().append(false); |
9dae56ea A |
2211 | } |
2212 | ||
6fe7ccc8 | 2213 | void BytecodeGenerator::pushFinallyContext(StatementNode* finallyBlock) |
9dae56ea | 2214 | { |
81345200 A |
2215 | // Reclaim free label scopes. |
2216 | while (m_labelScopes.size() && !m_labelScopes.last().refCount()) | |
2217 | m_labelScopes.removeLast(); | |
2218 | ||
9dae56ea A |
2219 | ControlFlowContext scope; |
2220 | scope.isFinallyBlock = true; | |
6fe7ccc8 A |
2221 | FinallyContext context = { |
2222 | finallyBlock, | |
ed1e77d3 A |
2223 | nullptr, |
2224 | nullptr, | |
2225 | static_cast<unsigned>(m_scopeContextStack.size()), | |
2226 | static_cast<unsigned>(m_switchContextStack.size()), | |
2227 | static_cast<unsigned>(m_forInContextStack.size()), | |
2228 | static_cast<unsigned>(m_tryContextStack.size()), | |
2229 | static_cast<unsigned>(m_labelScopes.size()), | |
2230 | m_finallyDepth, | |
2231 | m_localScopeDepth | |
2232 | }; | |
2233 | scope.finallyContext = context; | |
2234 | m_scopeContextStack.append(scope); | |
2235 | m_finallyDepth++; | |
2236 | } | |
2237 | ||
2238 | void BytecodeGenerator::pushIteratorCloseContext(RegisterID* iterator, ThrowableExpressionData* node) | |
2239 | { | |
2240 | // Reclaim free label scopes. | |
2241 | while (m_labelScopes.size() && !m_labelScopes.last().refCount()) | |
2242 | m_labelScopes.removeLast(); | |
2243 | ||
2244 | ControlFlowContext scope; | |
2245 | scope.isFinallyBlock = true; | |
2246 | FinallyContext context = { | |
2247 | nullptr, | |
2248 | iterator, | |
2249 | node, | |
93a37866 A |
2250 | static_cast<unsigned>(m_scopeContextStack.size()), |
2251 | static_cast<unsigned>(m_switchContextStack.size()), | |
2252 | static_cast<unsigned>(m_forInContextStack.size()), | |
2253 | static_cast<unsigned>(m_tryContextStack.size()), | |
2254 | static_cast<unsigned>(m_labelScopes.size()), | |
6fe7ccc8 | 2255 | m_finallyDepth, |
81345200 | 2256 | m_localScopeDepth |
6fe7ccc8 | 2257 | }; |
9dae56ea A |
2258 | scope.finallyContext = context; |
2259 | m_scopeContextStack.append(scope); | |
2260 | m_finallyDepth++; | |
2261 | } | |
2262 | ||
2263 | void BytecodeGenerator::popFinallyContext() | |
2264 | { | |
2265 | ASSERT(m_scopeContextStack.size()); | |
2266 | ASSERT(m_scopeContextStack.last().isFinallyBlock); | |
ed1e77d3 A |
2267 | ASSERT(m_scopeContextStack.last().finallyContext.finallyBlock); |
2268 | ASSERT(!m_scopeContextStack.last().finallyContext.iterator); | |
2269 | ASSERT(!m_scopeContextStack.last().finallyContext.enumerationNode); | |
2270 | ASSERT(m_finallyDepth > 0); | |
2271 | m_scopeContextStack.removeLast(); | |
2272 | m_finallyDepth--; | |
2273 | } | |
2274 | ||
2275 | void BytecodeGenerator::popIteratorCloseContext() | |
2276 | { | |
2277 | ASSERT(m_scopeContextStack.size()); | |
2278 | ASSERT(m_scopeContextStack.last().isFinallyBlock); | |
2279 | ASSERT(!m_scopeContextStack.last().finallyContext.finallyBlock); | |
2280 | ASSERT(m_scopeContextStack.last().finallyContext.iterator); | |
2281 | ASSERT(m_scopeContextStack.last().finallyContext.enumerationNode); | |
9dae56ea A |
2282 | ASSERT(m_finallyDepth > 0); |
2283 | m_scopeContextStack.removeLast(); | |
2284 | m_finallyDepth--; | |
2285 | } | |
2286 | ||
81345200 | 2287 | LabelScopePtr BytecodeGenerator::breakTarget(const Identifier& name) |
9dae56ea A |
2288 | { |
2289 | // Reclaim free label scopes. | |
ba379fdc A |
2290 | // |
2291 | // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()', | |
2292 | // however sometimes this appears to lead to GCC going a little haywire and entering the loop with | |
2293 | // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to | |
2294 | // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the | |
2295 | // loop condition is a workaround. | |
2296 | while (m_labelScopes.size()) { | |
2297 | if (m_labelScopes.last().refCount()) | |
2298 | break; | |
9dae56ea | 2299 | m_labelScopes.removeLast(); |
ba379fdc | 2300 | } |
9dae56ea A |
2301 | |
2302 | if (!m_labelScopes.size()) | |
81345200 | 2303 | return LabelScopePtr::null(); |
9dae56ea A |
2304 | |
2305 | // We special-case the following, which is a syntax error in Firefox: | |
2306 | // label: | |
2307 | // break; | |
2308 | if (name.isEmpty()) { | |
2309 | for (int i = m_labelScopes.size() - 1; i >= 0; --i) { | |
2310 | LabelScope* scope = &m_labelScopes[i]; | |
2311 | if (scope->type() != LabelScope::NamedLabel) { | |
2312 | ASSERT(scope->breakTarget()); | |
81345200 | 2313 | return LabelScopePtr(m_labelScopes, i); |
9dae56ea A |
2314 | } |
2315 | } | |
81345200 | 2316 | return LabelScopePtr::null(); |
9dae56ea A |
2317 | } |
2318 | ||
2319 | for (int i = m_labelScopes.size() - 1; i >= 0; --i) { | |
2320 | LabelScope* scope = &m_labelScopes[i]; | |
2321 | if (scope->name() && *scope->name() == name) { | |
2322 | ASSERT(scope->breakTarget()); | |
81345200 | 2323 | return LabelScopePtr(m_labelScopes, i); |
9dae56ea A |
2324 | } |
2325 | } | |
81345200 | 2326 | return LabelScopePtr::null(); |
9dae56ea A |
2327 | } |
2328 | ||
81345200 | 2329 | LabelScopePtr BytecodeGenerator::continueTarget(const Identifier& name) |
9dae56ea A |
2330 | { |
2331 | // Reclaim free label scopes. | |
2332 | while (m_labelScopes.size() && !m_labelScopes.last().refCount()) | |
2333 | m_labelScopes.removeLast(); | |
2334 | ||
2335 | if (!m_labelScopes.size()) | |
81345200 | 2336 | return LabelScopePtr::null(); |
9dae56ea A |
2337 | |
2338 | if (name.isEmpty()) { | |
2339 | for (int i = m_labelScopes.size() - 1; i >= 0; --i) { | |
2340 | LabelScope* scope = &m_labelScopes[i]; | |
2341 | if (scope->type() == LabelScope::Loop) { | |
2342 | ASSERT(scope->continueTarget()); | |
81345200 | 2343 | return LabelScopePtr(m_labelScopes, i); |
9dae56ea A |
2344 | } |
2345 | } | |
81345200 | 2346 | return LabelScopePtr::null(); |
9dae56ea A |
2347 | } |
2348 | ||
2349 | // Continue to the loop nested nearest to the label scope that matches | |
2350 | // 'name'. | |
81345200 | 2351 | LabelScopePtr result = LabelScopePtr::null(); |
9dae56ea A |
2352 | for (int i = m_labelScopes.size() - 1; i >= 0; --i) { |
2353 | LabelScope* scope = &m_labelScopes[i]; | |
2354 | if (scope->type() == LabelScope::Loop) { | |
2355 | ASSERT(scope->continueTarget()); | |
81345200 | 2356 | result = LabelScopePtr(m_labelScopes, i); |
9dae56ea A |
2357 | } |
2358 | if (scope->name() && *scope->name() == name) | |
81345200 | 2359 | return result; // may be null. |
9dae56ea | 2360 | } |
81345200 | 2361 | return LabelScopePtr::null(); |
9dae56ea A |
2362 | } |
2363 | ||
ed1e77d3 A |
2364 | void BytecodeGenerator::allocateAndEmitScope() |
2365 | { | |
2366 | m_scopeRegister = addVar(); | |
2367 | m_scopeRegister->ref(); | |
2368 | m_codeBlock->setScopeRegister(scopeRegister()->virtualRegister()); | |
2369 | emitGetScope(); | |
2370 | } | |
2371 | ||
2372 | void BytecodeGenerator::emitComplexPopScopes(RegisterID* scope, ControlFlowContext* topScope, ControlFlowContext* bottomScope) | |
9dae56ea A |
2373 | { |
2374 | while (topScope > bottomScope) { | |
2375 | // First we count the number of dynamic scopes we need to remove to get | |
2376 | // to a finally block. | |
2377 | int nNormalScopes = 0; | |
2378 | while (topScope > bottomScope) { | |
2379 | if (topScope->isFinallyBlock) | |
2380 | break; | |
2381 | ++nNormalScopes; | |
2382 | --topScope; | |
2383 | } | |
2384 | ||
2385 | if (nNormalScopes) { | |
2386 | // We need to remove a number of dynamic scopes to get to the next | |
2387 | // finally block | |
ed1e77d3 | 2388 | while (nNormalScopes--) { |
93a37866 | 2389 | emitOpcode(op_pop_scope); |
ed1e77d3 A |
2390 | instructions().append(scope->index()); |
2391 | } | |
9dae56ea | 2392 | |
93a37866 A |
2393 | // If topScope == bottomScope then there isn't a finally block left to emit. |
2394 | if (topScope == bottomScope) | |
2395 | return; | |
9dae56ea | 2396 | } |
6fe7ccc8 A |
2397 | |
2398 | Vector<ControlFlowContext> savedScopeContextStack; | |
2399 | Vector<SwitchInfo> savedSwitchContextStack; | |
ed1e77d3 | 2400 | Vector<std::unique_ptr<ForInContext>> savedForInContextStack; |
93a37866 A |
2401 | Vector<TryContext> poppedTryContexts; |
2402 | LabelScopeStore savedLabelScopes; | |
ba379fdc | 2403 | while (topScope > bottomScope && topScope->isFinallyBlock) { |
93a37866 A |
2404 | RefPtr<Label> beforeFinally = emitLabel(newLabel().get()); |
2405 | ||
6fe7ccc8 A |
2406 | // Save the current state of the world while instating the state of the world |
2407 | // for the finally block. | |
2408 | FinallyContext finallyContext = topScope->finallyContext; | |
2409 | bool flipScopes = finallyContext.scopeContextStackSize != m_scopeContextStack.size(); | |
2410 | bool flipSwitches = finallyContext.switchContextStackSize != m_switchContextStack.size(); | |
2411 | bool flipForIns = finallyContext.forInContextStackSize != m_forInContextStack.size(); | |
93a37866 | 2412 | bool flipTries = finallyContext.tryContextStackSize != m_tryContextStack.size(); |
6fe7ccc8 A |
2413 | bool flipLabelScopes = finallyContext.labelScopesSize != m_labelScopes.size(); |
2414 | int topScopeIndex = -1; | |
2415 | int bottomScopeIndex = -1; | |
2416 | if (flipScopes) { | |
2417 | topScopeIndex = topScope - m_scopeContextStack.begin(); | |
2418 | bottomScopeIndex = bottomScope - m_scopeContextStack.begin(); | |
2419 | savedScopeContextStack = m_scopeContextStack; | |
2420 | m_scopeContextStack.shrink(finallyContext.scopeContextStackSize); | |
2421 | } | |
2422 | if (flipSwitches) { | |
2423 | savedSwitchContextStack = m_switchContextStack; | |
2424 | m_switchContextStack.shrink(finallyContext.switchContextStackSize); | |
2425 | } | |
2426 | if (flipForIns) { | |
ed1e77d3 | 2427 | savedForInContextStack.swap(m_forInContextStack); |
6fe7ccc8 A |
2428 | m_forInContextStack.shrink(finallyContext.forInContextStackSize); |
2429 | } | |
93a37866 A |
2430 | if (flipTries) { |
2431 | while (m_tryContextStack.size() != finallyContext.tryContextStackSize) { | |
2432 | ASSERT(m_tryContextStack.size() > finallyContext.tryContextStackSize); | |
2433 | TryContext context = m_tryContextStack.last(); | |
2434 | m_tryContextStack.removeLast(); | |
2435 | TryRange range; | |
2436 | range.start = context.start; | |
2437 | range.end = beforeFinally; | |
2438 | range.tryData = context.tryData; | |
2439 | m_tryRanges.append(range); | |
2440 | poppedTryContexts.append(context); | |
2441 | } | |
2442 | } | |
6fe7ccc8 A |
2443 | if (flipLabelScopes) { |
2444 | savedLabelScopes = m_labelScopes; | |
2445 | while (m_labelScopes.size() > finallyContext.labelScopesSize) | |
2446 | m_labelScopes.removeLast(); | |
2447 | } | |
2448 | int savedFinallyDepth = m_finallyDepth; | |
2449 | m_finallyDepth = finallyContext.finallyDepth; | |
81345200 A |
2450 | int savedDynamicScopeDepth = m_localScopeDepth; |
2451 | m_localScopeDepth = finallyContext.dynamicScopeDepth; | |
6fe7ccc8 | 2452 | |
ed1e77d3 A |
2453 | if (finallyContext.finallyBlock) { |
2454 | // Emit the finally block. | |
2455 | emitNode(finallyContext.finallyBlock); | |
2456 | } else { | |
2457 | // Emit the IteratorClose block. | |
2458 | ASSERT(finallyContext.iterator); | |
2459 | emitIteratorClose(finallyContext.iterator, finallyContext.enumerationNode); | |
2460 | } | |
2461 | ||
93a37866 A |
2462 | RefPtr<Label> afterFinally = emitLabel(newLabel().get()); |
2463 | ||
6fe7ccc8 A |
2464 | // Restore the state of the world. |
2465 | if (flipScopes) { | |
2466 | m_scopeContextStack = savedScopeContextStack; | |
2467 | topScope = &m_scopeContextStack[topScopeIndex]; // assert it's within bounds | |
2468 | bottomScope = m_scopeContextStack.begin() + bottomScopeIndex; // don't assert, since it the index might be -1. | |
2469 | } | |
2470 | if (flipSwitches) | |
2471 | m_switchContextStack = savedSwitchContextStack; | |
2472 | if (flipForIns) | |
ed1e77d3 | 2473 | m_forInContextStack.swap(savedForInContextStack); |
93a37866 A |
2474 | if (flipTries) { |
2475 | ASSERT(m_tryContextStack.size() == finallyContext.tryContextStackSize); | |
2476 | for (unsigned i = poppedTryContexts.size(); i--;) { | |
2477 | TryContext context = poppedTryContexts[i]; | |
2478 | context.start = afterFinally; | |
2479 | m_tryContextStack.append(context); | |
2480 | } | |
2481 | poppedTryContexts.clear(); | |
2482 | } | |
6fe7ccc8 A |
2483 | if (flipLabelScopes) |
2484 | m_labelScopes = savedLabelScopes; | |
2485 | m_finallyDepth = savedFinallyDepth; | |
81345200 | 2486 | m_localScopeDepth = savedDynamicScopeDepth; |
6fe7ccc8 | 2487 | |
9dae56ea | 2488 | --topScope; |
ba379fdc | 2489 | } |
9dae56ea | 2490 | } |
9dae56ea A |
2491 | } |
2492 | ||
ed1e77d3 | 2493 | void BytecodeGenerator::emitPopScopes(RegisterID* scope, int targetScopeDepth) |
9dae56ea A |
2494 | { |
2495 | ASSERT(scopeDepth() - targetScopeDepth >= 0); | |
9dae56ea A |
2496 | |
2497 | size_t scopeDelta = scopeDepth() - targetScopeDepth; | |
2498 | ASSERT(scopeDelta <= m_scopeContextStack.size()); | |
2499 | if (!scopeDelta) | |
93a37866 | 2500 | return; |
9dae56ea | 2501 | |
93a37866 | 2502 | if (!m_finallyDepth) { |
ed1e77d3 | 2503 | while (scopeDelta--) { |
93a37866 | 2504 | emitOpcode(op_pop_scope); |
ed1e77d3 A |
2505 | instructions().append(scope->index()); |
2506 | } | |
93a37866 A |
2507 | return; |
2508 | } | |
f9bf01c6 | 2509 | |
ed1e77d3 | 2510 | emitComplexPopScopes(scope, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); |
9dae56ea A |
2511 | } |
2512 | ||
93a37866 A |
2513 | TryData* BytecodeGenerator::pushTry(Label* start) |
2514 | { | |
2515 | TryData tryData; | |
2516 | tryData.target = newLabel(); | |
2517 | tryData.targetScopeDepth = UINT_MAX; | |
ed1e77d3 | 2518 | tryData.handlerType = HandlerType::Illegal; |
93a37866 A |
2519 | m_tryData.append(tryData); |
2520 | TryData* result = &m_tryData.last(); | |
2521 | ||
2522 | TryContext tryContext; | |
2523 | tryContext.start = start; | |
2524 | tryContext.tryData = result; | |
2525 | ||
2526 | m_tryContextStack.append(tryContext); | |
2527 | ||
2528 | return result; | |
2529 | } | |
2530 | ||
ed1e77d3 | 2531 | void BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType handlerType) |
9dae56ea | 2532 | { |
14957cd0 | 2533 | m_usesExceptions = true; |
93a37866 A |
2534 | |
2535 | ASSERT_UNUSED(tryData, m_tryContextStack.last().tryData == tryData); | |
2536 | ||
2537 | TryRange tryRange; | |
2538 | tryRange.start = m_tryContextStack.last().start; | |
2539 | tryRange.end = end; | |
2540 | tryRange.tryData = m_tryContextStack.last().tryData; | |
2541 | m_tryRanges.append(tryRange); | |
2542 | m_tryContextStack.removeLast(); | |
2543 | ||
2544 | emitLabel(tryRange.tryData->target.get()); | |
81345200 | 2545 | tryRange.tryData->targetScopeDepth = m_localScopeDepth; |
ed1e77d3 | 2546 | tryRange.tryData->handlerType = handlerType; |
9dae56ea | 2547 | |
9dae56ea | 2548 | emitOpcode(op_catch); |
ed1e77d3 A |
2549 | instructions().append(exceptionRegister->index()); |
2550 | instructions().append(thrownValueRegister->index()); | |
9dae56ea A |
2551 | } |
2552 | ||
93a37866 | 2553 | void BytecodeGenerator::emitThrowReferenceError(const String& message) |
9dae56ea | 2554 | { |
93a37866 | 2555 | emitOpcode(op_throw_static_error); |
ed1e77d3 | 2556 | instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, message)))->index()); |
93a37866 | 2557 | instructions().append(true); |
9dae56ea A |
2558 | } |
2559 | ||
ed1e77d3 A |
2560 | void BytecodeGenerator::emitThrowTypeError(const String& message) |
2561 | { | |
2562 | emitOpcode(op_throw_static_error); | |
2563 | instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, message)))->index()); | |
2564 | instructions().append(false); | |
2565 | } | |
2566 | ||
2567 | void BytecodeGenerator::emitPushFunctionNameScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes) | |
81345200 A |
2568 | { |
2569 | emitOpcode(op_push_name_scope); | |
ed1e77d3 | 2570 | instructions().append(dst->index()); |
81345200 | 2571 | instructions().append(value->index()); |
ed1e77d3 A |
2572 | instructions().append(addConstantValue(SymbolTable::createNameScopeTable(*vm(), property, attributes))->index()); |
2573 | instructions().append(JSNameScope::FunctionNameScope); | |
81345200 A |
2574 | } |
2575 | ||
ed1e77d3 | 2576 | void BytecodeGenerator::emitPushCatchScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes) |
9dae56ea A |
2577 | { |
2578 | ControlFlowContext context; | |
2579 | context.isFinallyBlock = false; | |
2580 | m_scopeContextStack.append(context); | |
81345200 | 2581 | m_localScopeDepth++; |
ba379fdc | 2582 | |
93a37866 | 2583 | emitOpcode(op_push_name_scope); |
ed1e77d3 | 2584 | instructions().append(dst->index()); |
9dae56ea | 2585 | instructions().append(value->index()); |
ed1e77d3 A |
2586 | instructions().append(addConstantValue(SymbolTable::createNameScopeTable(*vm(), property, attributes))->index()); |
2587 | instructions().append(JSNameScope::CatchScope); | |
9dae56ea A |
2588 | } |
2589 | ||
2590 | void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type) | |
2591 | { | |
93a37866 | 2592 | SwitchInfo info = { static_cast<uint32_t>(instructions().size()), type }; |
9dae56ea A |
2593 | switch (type) { |
2594 | case SwitchInfo::SwitchImmediate: | |
2595 | emitOpcode(op_switch_imm); | |
2596 | break; | |
2597 | case SwitchInfo::SwitchCharacter: | |
2598 | emitOpcode(op_switch_char); | |
2599 | break; | |
2600 | case SwitchInfo::SwitchString: | |
2601 | emitOpcode(op_switch_string); | |
2602 | break; | |
2603 | default: | |
93a37866 | 2604 | RELEASE_ASSERT_NOT_REACHED(); |
9dae56ea A |
2605 | } |
2606 | ||
2607 | instructions().append(0); // place holder for table index | |
2608 | instructions().append(0); // place holder for default target | |
2609 | instructions().append(scrutineeRegister->index()); | |
2610 | m_switchContextStack.append(info); | |
2611 | } | |
2612 | ||
2613 | static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max) | |
2614 | { | |
2615 | UNUSED_PARAM(max); | |
2616 | ASSERT(node->isNumber()); | |
2617 | double value = static_cast<NumberNode*>(node)->value(); | |
2618 | int32_t key = static_cast<int32_t>(value); | |
9dae56ea A |
2619 | ASSERT(key == value); |
2620 | ASSERT(key >= min); | |
2621 | ASSERT(key <= max); | |
2622 | return key - min; | |
2623 | } | |
2624 | ||
9dae56ea A |
2625 | static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max) |
2626 | { | |
2627 | UNUSED_PARAM(max); | |
2628 | ASSERT(node->isString()); | |
14957cd0 | 2629 | StringImpl* clause = static_cast<StringNode*>(node)->value().impl(); |
4e4e5a6f | 2630 | ASSERT(clause->length() == 1); |
9dae56ea | 2631 | |
6fe7ccc8 | 2632 | int32_t key = (*clause)[0]; |
9dae56ea A |
2633 | ASSERT(key >= min); |
2634 | ASSERT(key <= max); | |
2635 | return key - min; | |
2636 | } | |
2637 | ||
81345200 A |
2638 | static void prepareJumpTableForSwitch( |
2639 | UnlinkedSimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, | |
2640 | RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max, | |
2641 | int32_t (*keyGetter)(ExpressionNode*, int32_t min, int32_t max)) | |
9dae56ea A |
2642 | { |
2643 | jumpTable.min = min; | |
2644 | jumpTable.branchOffsets.resize(max - min + 1); | |
2645 | jumpTable.branchOffsets.fill(0); | |
2646 | for (uint32_t i = 0; i < clauseCount; ++i) { | |
2647 | // We're emitting this after the clause labels should have been fixed, so | |
2648 | // the labels should not be "forward" references | |
2649 | ASSERT(!labels[i]->isForward()); | |
81345200 | 2650 | jumpTable.add(keyGetter(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); |
9dae56ea A |
2651 | } |
2652 | } | |
2653 | ||
93a37866 | 2654 | static void prepareJumpTableForStringSwitch(UnlinkedStringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes) |
9dae56ea A |
2655 | { |
2656 | for (uint32_t i = 0; i < clauseCount; ++i) { | |
2657 | // We're emitting this after the clause labels should have been fixed, so | |
2658 | // the labels should not be "forward" references | |
2659 | ASSERT(!labels[i]->isForward()); | |
2660 | ||
2661 | ASSERT(nodes[i]->isString()); | |
14957cd0 | 2662 | StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl(); |
93a37866 | 2663 | jumpTable.offsetTable.add(clause, labels[i]->bind(switchAddress, switchAddress + 3)); |
9dae56ea A |
2664 | } |
2665 | } | |
2666 | ||
2667 | void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, Label* defaultLabel, int32_t min, int32_t max) | |
2668 | { | |
2669 | SwitchInfo switchInfo = m_switchContextStack.last(); | |
2670 | m_switchContextStack.removeLast(); | |
81345200 A |
2671 | |
2672 | switch (switchInfo.switchType) { | |
2673 | case SwitchInfo::SwitchImmediate: | |
2674 | case SwitchInfo::SwitchCharacter: { | |
2675 | instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfSwitchJumpTables(); | |
f9bf01c6 | 2676 | instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); |
9dae56ea | 2677 | |
81345200 A |
2678 | UnlinkedSimpleJumpTable& jumpTable = m_codeBlock->addSwitchJumpTable(); |
2679 | prepareJumpTableForSwitch( | |
2680 | jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max, | |
2681 | switchInfo.switchType == SwitchInfo::SwitchImmediate | |
2682 | ? keyForImmediateSwitch | |
2683 | : keyForCharacterSwitch); | |
2684 | break; | |
2685 | } | |
9dae56ea | 2686 | |
81345200 | 2687 | case SwitchInfo::SwitchString: { |
9dae56ea | 2688 | instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables(); |
f9bf01c6 | 2689 | instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); |
9dae56ea | 2690 | |
93a37866 | 2691 | UnlinkedStringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable(); |
f9bf01c6 | 2692 | prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes); |
81345200 A |
2693 | break; |
2694 | } | |
2695 | ||
2696 | default: | |
2697 | RELEASE_ASSERT_NOT_REACHED(); | |
2698 | break; | |
9dae56ea A |
2699 | } |
2700 | } | |
2701 | ||
2702 | RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() | |
2703 | { | |
2704 | // It would be nice to do an even better job of identifying exactly where the expression is. | |
2705 | // And we could make the caller pass the node pointer in, if there was some way of getting | |
2706 | // that from an arbitrary node. However, calling emitExpressionInfo without any useful data | |
2707 | // is still good enough to get us an accurate line number. | |
14957cd0 A |
2708 | m_expressionTooDeep = true; |
2709 | return newTemporary(); | |
2710 | } | |
2711 | ||
6fe7ccc8 | 2712 | bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber) |
14957cd0 | 2713 | { |
ed1e77d3 A |
2714 | RegisterID* registerID = variable(ident).local(); |
2715 | if (!registerID) | |
2716 | return false; | |
6fe7ccc8 | 2717 | return registerID->index() == CallFrame::argumentOffset(argumentNumber); |
9dae56ea A |
2718 | } |
2719 | ||
93a37866 A |
2720 | void BytecodeGenerator::emitReadOnlyExceptionIfNeeded() |
2721 | { | |
2722 | if (!isStrictMode()) | |
2723 | return; | |
2724 | emitOpcode(op_throw_static_error); | |
ed1e77d3 | 2725 | instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, StrictModeReadonlyPropertyWriteError)))->index()); |
93a37866 A |
2726 | instructions().append(false); |
2727 | } | |
81345200 A |
2728 | |
2729 | void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack) | |
2730 | { | |
ed1e77d3 A |
2731 | RefPtr<RegisterID> subject = newTemporary(); |
2732 | emitNode(subject.get(), subjectNode); | |
2733 | RefPtr<RegisterID> iterator = emitGetById(newTemporary(), subject.get(), propertyNames().iteratorSymbol); | |
2734 | { | |
2735 | CallArguments args(*this, nullptr); | |
2736 | emitMove(args.thisRegister(), subject.get()); | |
2737 | emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd()); | |
2738 | } | |
81345200 | 2739 | |
ed1e77d3 A |
2740 | RefPtr<Label> loopDone = newLabel(); |
2741 | // RefPtr<Register> iterator's lifetime must be longer than IteratorCloseContext. | |
2742 | pushIteratorCloseContext(iterator.get(), node); | |
2743 | { | |
81345200 | 2744 | LabelScopePtr scope = newLabelScope(LabelScope::Loop); |
ed1e77d3 A |
2745 | RefPtr<RegisterID> value = newTemporary(); |
2746 | emitLoad(value.get(), jsUndefined()); | |
2747 | ||
2748 | emitJump(scope->continueTarget()); | |
2749 | ||
81345200 | 2750 | RefPtr<Label> loopStart = newLabel(); |
81345200 A |
2751 | emitLabel(loopStart.get()); |
2752 | emitLoopHint(); | |
ed1e77d3 A |
2753 | |
2754 | RefPtr<Label> tryStartLabel = newLabel(); | |
2755 | emitLabel(tryStartLabel.get()); | |
2756 | TryData* tryData = pushTry(tryStartLabel.get()); | |
81345200 | 2757 | callBack(*this, value.get()); |
ed1e77d3 A |
2758 | emitJump(scope->continueTarget()); |
2759 | ||
2760 | // IteratorClose sequence for throw-ed control flow. | |
2761 | { | |
2762 | RefPtr<Label> catchHere = emitLabel(newLabel().get()); | |
2763 | RefPtr<RegisterID> exceptionRegister = newTemporary(); | |
2764 | RefPtr<RegisterID> thrownValueRegister = newTemporary(); | |
2765 | popTryAndEmitCatch(tryData, exceptionRegister.get(), | |
2766 | thrownValueRegister.get(), catchHere.get(), HandlerType::SynthesizedFinally); | |
2767 | ||
2768 | RefPtr<Label> catchDone = newLabel(); | |
2769 | ||
2770 | RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword); | |
2771 | emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), catchDone.get()); | |
2772 | ||
2773 | RefPtr<Label> returnCallTryStart = newLabel(); | |
2774 | emitLabel(returnCallTryStart.get()); | |
2775 | TryData* returnCallTryData = pushTry(returnCallTryStart.get()); | |
2776 | ||
2777 | CallArguments returnArguments(*this, nullptr); | |
2778 | emitMove(returnArguments.thisRegister(), iterator.get()); | |
2779 | emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd()); | |
2780 | ||
2781 | emitLabel(catchDone.get()); | |
2782 | emitThrow(exceptionRegister.get()); | |
2783 | ||
2784 | // Absorb exception. | |
2785 | popTryAndEmitCatch(returnCallTryData, newTemporary(), | |
2786 | newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally); | |
2787 | emitThrow(exceptionRegister.get()); | |
2788 | } | |
2789 | ||
81345200 | 2790 | emitLabel(scope->continueTarget()); |
ed1e77d3 A |
2791 | { |
2792 | emitIteratorNext(value.get(), iterator.get(), node); | |
2793 | emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get()); | |
2794 | emitGetById(value.get(), value.get(), propertyNames().value); | |
2795 | emitJump(loopStart.get()); | |
2796 | } | |
2797 | ||
81345200 | 2798 | emitLabel(scope->breakTarget()); |
81345200 A |
2799 | } |
2800 | ||
ed1e77d3 A |
2801 | // IteratorClose sequence for break-ed control flow. |
2802 | popIteratorCloseContext(); | |
2803 | emitIteratorClose(iterator.get(), node); | |
2804 | emitLabel(loopDone.get()); | |
2805 | } | |
2806 | ||
2807 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) | |
2808 | RegisterID* BytecodeGenerator::emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode* taggedTemplate) | |
2809 | { | |
2810 | TemplateRegistryKey::StringVector rawStrings; | |
2811 | TemplateRegistryKey::StringVector cookedStrings; | |
2812 | ||
2813 | TemplateStringListNode* templateString = taggedTemplate->templateLiteral()->templateStrings(); | |
2814 | for (; templateString; templateString = templateString->next()) { | |
2815 | rawStrings.append(templateString->value()->raw().impl()); | |
2816 | cookedStrings.append(templateString->value()->cooked().impl()); | |
2817 | } | |
2818 | ||
2819 | RefPtr<RegisterID> getTemplateObject = nullptr; | |
2820 | Variable var = variable(propertyNames().getTemplateObjectPrivateName); | |
2821 | if (RegisterID* local = var.local()) | |
2822 | getTemplateObject = emitMove(newTemporary(), local); | |
2823 | else { | |
2824 | getTemplateObject = newTemporary(); | |
2825 | RefPtr<RegisterID> scope = newTemporary(); | |
2826 | moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var)); | |
2827 | emitGetFromScope(getTemplateObject.get(), scope.get(), var, ThrowIfNotFound); | |
2828 | } | |
2829 | ||
2830 | CallArguments arguments(*this, nullptr); | |
2831 | emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(TemplateRegistryKey(rawStrings, cookedStrings)))); | |
2832 | return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd()); | |
2833 | } | |
2834 | #endif | |
2835 | ||
2836 | RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base) | |
2837 | { | |
2838 | emitOpcode(op_get_enumerable_length); | |
2839 | instructions().append(dst->index()); | |
2840 | instructions().append(base->index()); | |
2841 | return dst; | |
2842 | } | |
2843 | ||
2844 | RegisterID* BytecodeGenerator::emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName) | |
2845 | { | |
2846 | emitOpcode(op_has_generic_property); | |
2847 | instructions().append(dst->index()); | |
2848 | instructions().append(base->index()); | |
2849 | instructions().append(propertyName->index()); | |
2850 | return dst; | |
2851 | } | |
2852 | ||
2853 | RegisterID* BytecodeGenerator::emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName) | |
2854 | { | |
2855 | UnlinkedArrayProfile arrayProfile = newArrayProfile(); | |
2856 | emitOpcode(op_has_indexed_property); | |
2857 | instructions().append(dst->index()); | |
2858 | instructions().append(base->index()); | |
2859 | instructions().append(propertyName->index()); | |
2860 | instructions().append(arrayProfile); | |
2861 | return dst; | |
2862 | } | |
2863 | ||
2864 | RegisterID* BytecodeGenerator::emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator) | |
2865 | { | |
2866 | emitOpcode(op_has_structure_property); | |
2867 | instructions().append(dst->index()); | |
2868 | instructions().append(base->index()); | |
2869 | instructions().append(propertyName->index()); | |
2870 | instructions().append(enumerator->index()); | |
2871 | return dst; | |
2872 | } | |
2873 | ||
2874 | RegisterID* BytecodeGenerator::emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base) | |
2875 | { | |
2876 | emitOpcode(op_get_property_enumerator); | |
2877 | instructions().append(dst->index()); | |
2878 | instructions().append(base->index()); | |
2879 | return dst; | |
2880 | } | |
2881 | ||
2882 | RegisterID* BytecodeGenerator::emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index) | |
2883 | { | |
2884 | emitOpcode(op_enumerator_structure_pname); | |
2885 | instructions().append(dst->index()); | |
2886 | instructions().append(enumerator->index()); | |
2887 | instructions().append(index->index()); | |
2888 | return dst; | |
2889 | } | |
2890 | ||
2891 | RegisterID* BytecodeGenerator::emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index) | |
2892 | { | |
2893 | emitOpcode(op_enumerator_generic_pname); | |
2894 | instructions().append(dst->index()); | |
2895 | instructions().append(enumerator->index()); | |
2896 | instructions().append(index->index()); | |
2897 | return dst; | |
2898 | } | |
2899 | ||
2900 | RegisterID* BytecodeGenerator::emitToIndexString(RegisterID* dst, RegisterID* index) | |
2901 | { | |
2902 | emitOpcode(op_to_index_string); | |
2903 | instructions().append(dst->index()); | |
2904 | instructions().append(index->index()); | |
2905 | return dst; | |
2906 | } | |
2907 | ||
2908 | ||
2909 | RegisterID* BytecodeGenerator::emitIsObject(RegisterID* dst, RegisterID* src) | |
2910 | { | |
2911 | emitOpcode(op_is_object); | |
2912 | instructions().append(dst->index()); | |
2913 | instructions().append(src->index()); | |
2914 | return dst; | |
2915 | } | |
2916 | ||
2917 | RegisterID* BytecodeGenerator::emitIsUndefined(RegisterID* dst, RegisterID* src) | |
2918 | { | |
2919 | emitOpcode(op_is_undefined); | |
2920 | instructions().append(dst->index()); | |
2921 | instructions().append(src->index()); | |
2922 | return dst; | |
2923 | } | |
2924 | ||
2925 | RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node) | |
2926 | { | |
81345200 | 2927 | { |
ed1e77d3 A |
2928 | RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next); |
2929 | CallArguments nextArguments(*this, nullptr); | |
2930 | emitMove(nextArguments.thisRegister(), iterator); | |
2931 | emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd()); | |
2932 | } | |
2933 | { | |
2934 | RefPtr<Label> typeIsObject = newLabel(); | |
2935 | emitJumpIfTrue(emitIsObject(newTemporary(), dst), typeIsObject.get()); | |
2936 | emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object.")); | |
2937 | emitLabel(typeIsObject.get()); | |
81345200 | 2938 | } |
ed1e77d3 A |
2939 | return dst; |
2940 | } | |
2941 | ||
2942 | void BytecodeGenerator::emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node) | |
2943 | { | |
2944 | RefPtr<Label> done = newLabel(); | |
2945 | RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator, propertyNames().returnKeyword); | |
2946 | emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), done.get()); | |
2947 | ||
81345200 | 2948 | RefPtr<RegisterID> value = newTemporary(); |
ed1e77d3 A |
2949 | CallArguments returnArguments(*this, nullptr); |
2950 | emitMove(returnArguments.thisRegister(), iterator); | |
2951 | emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd()); | |
2952 | emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), done.get()); | |
2953 | emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object.")); | |
2954 | emitLabel(done.get()); | |
2955 | } | |
2956 | ||
2957 | void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, RegisterID* indexRegister) | |
2958 | { | |
2959 | if (!localRegister) | |
2960 | return; | |
2961 | m_forInContextStack.append(std::make_unique<IndexedForInContext>(localRegister, indexRegister)); | |
2962 | } | |
2963 | ||
2964 | void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister) | |
2965 | { | |
2966 | if (!localRegister) | |
2967 | return; | |
2968 | m_forInContextStack.removeLast(); | |
2969 | } | |
2970 | ||
2971 | void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister) | |
2972 | { | |
2973 | if (!localRegister) | |
2974 | return; | |
2975 | m_forInContextStack.append(std::make_unique<StructureForInContext>(localRegister, indexRegister, propertyRegister, enumeratorRegister)); | |
2976 | } | |
2977 | ||
2978 | void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister) | |
2979 | { | |
2980 | if (!localRegister) | |
2981 | return; | |
2982 | m_forInContextStack.removeLast(); | |
2983 | } | |
2984 | ||
2985 | void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister) | |
2986 | { | |
2987 | // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if | |
2988 | // either of the following conditions is true: | |
2989 | // | |
2990 | // (1) The loop iteration variable is re-assigned within the body of the loop. | |
2991 | // (2) The loop iteration variable is captured in the lexical scope of the function. | |
2992 | // | |
2993 | // These two situations occur sufficiently rarely that it's okay to use this style of | |
2994 | // "analysis" to make iteration faster. If we didn't want to do this, we would either have | |
2995 | // to perform some flow-sensitive analysis to see if/when the loop iteration variable was | |
2996 | // reassigned, or we'd have to resort to runtime checks to see if the variable had been | |
2997 | // reassigned from its original value. | |
2998 | for (size_t i = m_forInContextStack.size(); i > 0; i--) { | |
2999 | ForInContext* context = m_forInContextStack[i - 1].get(); | |
3000 | if (context->local() != localRegister) | |
3001 | continue; | |
3002 | context->invalidate(); | |
3003 | break; | |
3004 | } | |
81345200 | 3005 | } |
93a37866 | 3006 | |
9dae56ea | 3007 | } // namespace JSC |