1/* 2 * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#include "UnlinkedCodeBlock.h" 29 30#include "BytecodeGenerator.h" 31#include "ClassInfo.h" 32#include "CodeCache.h" 33#include "Executable.h" 34#include "JSString.h" 35#include "JSCInlines.h" 36#include "Parser.h" 37#include "SourceProvider.h" 38#include "Structure.h" 39#include "SymbolTable.h" 40#include "UnlinkedInstructionStream.h" 41#include <wtf/DataLog.h> 42 43namespace JSC { 44 45const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) }; 46const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) }; 47const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) }; 48const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) }; 49const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) }; 50const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) }; 51 52static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, UnlinkedFunctionKind functionKind, bool bodyIncludesBraces, ParserError& error) 53{ 54 RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&vm, source, executable->parameters(), executable->name(), executable->toStrictness(), JSParseFunctionCode, error, 0, bodyIncludesBraces); 55 56 if (!body) { 57 ASSERT(error.m_type != ParserError::ErrorNone); 58 return 0; 59 } 60 61 if (executable->forceUsesArguments()) 62 body->setUsesArguments(); 63 body->finishParsing(executable->parameters(), executable->name(), executable->functionMode()); 64 executable->recordParse(body->features(), body->hasCapturedVariables()); 65 66 UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction)); 67 OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, body.get(), result, debuggerMode, profilerMode))); 68 error = generator->generate(); 69 body->destroyData(); 70 if (error.m_type != ParserError::ErrorNone) 71 return 0; 72 return result; 73} 74 75unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v) 76{ 77 unsigned numberOfConstants = numberOfConstantRegisters(); 78 for (unsigned i = 0; i < numberOfConstants; ++i) { 79 if (getConstant(FirstConstantRegisterIndex + i) == v) 80 return i; 81 } 82 return addConstant(v); 83} 84 85UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind kind) 86 : Base(*vm, structure) 87 , m_numCapturedVariables(node->capturedVariableCount()) 88 , m_forceUsesArguments(node->usesArguments()) 89 , m_isInStrictContext(node->isStrictMode()) 90 , m_hasCapturedVariables(node->hasCapturedVariables()) 91 , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction) 92 , m_name(node->ident()) 93 , m_inferredName(node->inferredName()) 94 , m_parameters(node->parameters()) 95 , m_firstLineOffset(node->firstLine() - source.firstLine()) 96 , m_lineCount(node->lastLine() - node->firstLine()) 97 , m_unlinkedFunctionNameStart(node->functionNameStart() - source.startOffset()) 98 , m_unlinkedBodyStartColumn(node->startColumn()) 99 , m_unlinkedBodyEndColumn(m_lineCount ? node->endColumn() : node->endColumn() - node->startColumn()) 100 , m_startOffset(node->source().startOffset() - source.startOffset()) 101 , m_sourceLength(node->source().length()) 102 , m_features(node->features()) 103 , m_functionMode(node->functionMode()) 104{ 105} 106 107size_t UnlinkedFunctionExecutable::parameterCount() const 108{ 109 return m_parameters->size(); 110} 111 112void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) 113{ 114 UnlinkedFunctionExecutable* thisObject = jsCast<UnlinkedFunctionExecutable*>(cell); 115 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 116 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 117 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 118 Base::visitChildren(thisObject, visitor); 119 visitor.append(&thisObject->m_codeBlockForCall); 120 visitor.append(&thisObject->m_codeBlockForConstruct); 121 visitor.append(&thisObject->m_nameValue); 122 visitor.append(&thisObject->m_symbolTableForCall); 123 visitor.append(&thisObject->m_symbolTableForConstruct); 124} 125 126FunctionExecutable* UnlinkedFunctionExecutable::link(VM& vm, const SourceCode& source, size_t lineOffset) 127{ 128 unsigned firstLine = lineOffset + m_firstLineOffset; 129 bool startColumnIsOnFirstSourceLine = !m_firstLineOffset; 130 unsigned startColumn = m_unlinkedBodyStartColumn + (startColumnIsOnFirstSourceLine ? source.startColumn() : 1); 131 bool endColumnIsOnStartLine = !m_lineCount; 132 unsigned endColumn = m_unlinkedBodyEndColumn + (endColumnIsOnStartLine ? startColumn : 1); 133 SourceCode code(source.provider(), m_startOffset, m_startOffset + m_sourceLength, firstLine, startColumn); 134 return FunctionExecutable::create(vm, code, this, firstLine, firstLine + m_lineCount, startColumn, endColumn); 135} 136 137UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger*, const SourceCode& source, JSObject** exception) 138{ 139 ParserError error; 140 VM& vm = exec->vm(); 141 CodeCache* codeCache = vm.codeCache(); 142 UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(vm, name, source, error); 143 144 if (exec->lexicalGlobalObject()->hasDebugger()) 145 exec->lexicalGlobalObject()->debugger()->sourceParsed(exec, source.provider(), error.m_line, error.m_message); 146 147 if (error.m_type != ParserError::ErrorNone) { 148 *exception = error.toErrorObject(exec->lexicalGlobalObject(), source); 149 return 0; 150 } 151 152 return executable; 153} 154 155UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, bool bodyIncludesBraces, ParserError& error) 156{ 157 switch (specializationKind) { 158 case CodeForCall: 159 if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) 160 return codeBlock; 161 break; 162 case CodeForConstruct: 163 if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) 164 return codeBlock; 165 break; 166 } 167 168 UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(vm, this, source, specializationKind, debuggerMode, profilerMode, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, bodyIncludesBraces, error); 169 170 if (error.m_type != ParserError::ErrorNone) 171 return 0; 172 173 switch (specializationKind) { 174 case CodeForCall: 175 m_codeBlockForCall.set(vm, this, result); 176 m_symbolTableForCall.set(vm, this, result->symbolTable()); 177 break; 178 case CodeForConstruct: 179 m_codeBlockForConstruct.set(vm, this, result); 180 m_symbolTableForConstruct.set(vm, this, result->symbolTable()); 181 break; 182 } 183 return result; 184} 185 186String UnlinkedFunctionExecutable::paramString() const 187{ 188 FunctionParameters& parameters = *m_parameters; 189 StringBuilder builder; 190 for (size_t pos = 0; pos < parameters.size(); ++pos) { 191 if (!builder.isEmpty()) 192 builder.appendLiteral(", "); 193 parameters.at(pos)->toString(builder); 194 } 195 return builder.toString(); 196} 197 198UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info) 199 : Base(*vm, structure) 200 , m_numVars(0) 201 , m_numCalleeRegisters(0) 202 , m_numParameters(0) 203 , m_vm(vm) 204 , m_argumentsRegister(VirtualRegister()) 205 , m_globalObjectRegister(VirtualRegister()) 206 , m_needsFullScopeChain(info.m_needsActivation) 207 , m_usesEval(info.m_usesEval) 208 , m_isNumericCompareFunction(false) 209 , m_isStrictMode(info.m_isStrictMode) 210 , m_isConstructor(info.m_isConstructor) 211 , m_hasCapturedVariables(false) 212 , m_isBuiltinFunction(info.m_isBuiltinFunction) 213 , m_firstLine(0) 214 , m_lineCount(0) 215 , m_endColumn(UINT_MAX) 216 , m_features(0) 217 , m_codeType(codeType) 218 , m_arrayProfileCount(0) 219 , m_arrayAllocationProfileCount(0) 220 , m_objectAllocationProfileCount(0) 221 , m_valueProfileCount(0) 222 , m_llintCallLinkInfoCount(0) 223#if ENABLE(BYTECODE_COMMENTS) 224 , m_bytecodeCommentIterator(0) 225#endif 226{ 227 228} 229 230void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) 231{ 232 UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell); 233 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 234 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 235 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 236 Base::visitChildren(thisObject, visitor); 237 visitor.append(&thisObject->m_symbolTable); 238 for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr) 239 visitor.append(ptr); 240 for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr) 241 visitor.append(ptr); 242 visitor.appendValues(thisObject->m_constantRegisters.data(), thisObject->m_constantRegisters.size()); 243 if (thisObject->m_rareData) { 244 for (size_t i = 0, end = thisObject->m_rareData->m_regexps.size(); i != end; i++) 245 visitor.append(&thisObject->m_rareData->m_regexps[i]); 246 } 247} 248 249int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) 250{ 251 ASSERT(bytecodeOffset < instructions().count()); 252 int divot; 253 int startOffset; 254 int endOffset; 255 unsigned line; 256 unsigned column; 257 expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column); 258 return line; 259} 260 261inline void UnlinkedCodeBlock::getLineAndColumn(ExpressionRangeInfo& info, 262 unsigned& line, unsigned& column) 263{ 264 switch (info.mode) { 265 case ExpressionRangeInfo::FatLineMode: 266 info.decodeFatLineMode(line, column); 267 break; 268 case ExpressionRangeInfo::FatColumnMode: 269 info.decodeFatColumnMode(line, column); 270 break; 271 case ExpressionRangeInfo::FatLineAndColumnMode: { 272 unsigned fatIndex = info.position; 273 ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex]; 274 line = fatPos.line; 275 column = fatPos.column; 276 break; 277 } 278 } // switch 279} 280 281#ifndef NDEBUG 282static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column) 283{ 284 const auto& instructions = instructionStream.unpackForDebugging(); 285 OpcodeID opcode = instructions[instructionOffset].u.opcode; 286 const char* event = ""; 287 if (opcode == op_debug) { 288 switch (instructions[instructionOffset + 1].u.operand) { 289 case WillExecuteProgram: event = " WillExecuteProgram"; break; 290 case DidExecuteProgram: event = " DidExecuteProgram"; break; 291 case DidEnterCallFrame: event = " DidEnterCallFrame"; break; 292 case DidReachBreakpoint: event = " DidReachBreakpoint"; break; 293 case WillLeaveCallFrame: event = " WillLeaveCallFrame"; break; 294 case WillExecuteStatement: event = " WillExecuteStatement"; break; 295 } 296 } 297 dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event); 298} 299 300void UnlinkedCodeBlock::dumpExpressionRangeInfo() 301{ 302 Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo; 303 304 size_t size = m_expressionInfo.size(); 305 dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size); 306 for (size_t i = 0; i < size; i++) { 307 ExpressionRangeInfo& info = expressionInfo[i]; 308 unsigned line; 309 unsigned column; 310 getLineAndColumn(info, line, column); 311 dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column); 312 } 313 dataLog("}\n"); 314} 315#endif 316 317void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, 318 int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) 319{ 320 ASSERT(bytecodeOffset < instructions().count()); 321 322 if (!m_expressionInfo.size()) { 323 startOffset = 0; 324 endOffset = 0; 325 divot = 0; 326 line = 0; 327 column = 0; 328 return; 329 } 330 331 Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo; 332 333 int low = 0; 334 int high = expressionInfo.size(); 335 while (low < high) { 336 int mid = low + (high - low) / 2; 337 if (expressionInfo[mid].instructionOffset <= bytecodeOffset) 338 low = mid + 1; 339 else 340 high = mid; 341 } 342 343 if (!low) 344 low = 1; 345 346 ExpressionRangeInfo& info = expressionInfo[low - 1]; 347 startOffset = info.startOffset; 348 endOffset = info.endOffset; 349 divot = info.divotPoint; 350 getLineAndColumn(info, line, column); 351} 352 353void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset, 354 int divot, int startOffset, int endOffset, unsigned line, unsigned column) 355{ 356 if (divot > ExpressionRangeInfo::MaxDivot) { 357 // Overflow has occurred, we can only give line number info for errors for this region 358 divot = 0; 359 startOffset = 0; 360 endOffset = 0; 361 } else if (startOffset > ExpressionRangeInfo::MaxOffset) { 362 // If the start offset is out of bounds we clear both offsets 363 // so we only get the divot marker. Error message will have to be reduced 364 // to line and charPosition number. 365 startOffset = 0; 366 endOffset = 0; 367 } else if (endOffset > ExpressionRangeInfo::MaxOffset) { 368 // The end offset is only used for additional context, and is much more likely 369 // to overflow (eg. function call arguments) so we are willing to drop it without 370 // dropping the rest of the range. 371 endOffset = 0; 372 } 373 374 unsigned positionMode = 375 (line <= ExpressionRangeInfo::MaxFatLineModeLine && column <= ExpressionRangeInfo::MaxFatLineModeColumn) 376 ? ExpressionRangeInfo::FatLineMode 377 : (line <= ExpressionRangeInfo::MaxFatColumnModeLine && column <= ExpressionRangeInfo::MaxFatColumnModeColumn) 378 ? ExpressionRangeInfo::FatColumnMode 379 : ExpressionRangeInfo::FatLineAndColumnMode; 380 381 ExpressionRangeInfo info; 382 info.instructionOffset = instructionOffset; 383 info.divotPoint = divot; 384 info.startOffset = startOffset; 385 info.endOffset = endOffset; 386 387 info.mode = positionMode; 388 switch (positionMode) { 389 case ExpressionRangeInfo::FatLineMode: 390 info.encodeFatLineMode(line, column); 391 break; 392 case ExpressionRangeInfo::FatColumnMode: 393 info.encodeFatColumnMode(line, column); 394 break; 395 case ExpressionRangeInfo::FatLineAndColumnMode: { 396 createRareDataIfNecessary(); 397 unsigned fatIndex = m_rareData->m_expressionInfoFatPositions.size(); 398 ExpressionRangeInfo::FatPosition fatPos = { line, column }; 399 m_rareData->m_expressionInfoFatPositions.append(fatPos); 400 info.position = fatIndex; 401 } 402 } // switch 403 404 m_expressionInfo.append(info); 405} 406 407void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) 408{ 409 UnlinkedProgramCodeBlock* thisObject = jsCast<UnlinkedProgramCodeBlock*>(cell); 410 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 411 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 412 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 413 Base::visitChildren(thisObject, visitor); 414 for (size_t i = 0, end = thisObject->m_functionDeclarations.size(); i != end; i++) 415 visitor.append(&thisObject->m_functionDeclarations[i].second); 416} 417 418UnlinkedCodeBlock::~UnlinkedCodeBlock() 419{ 420} 421 422void UnlinkedProgramCodeBlock::destroy(JSCell* cell) 423{ 424 jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock(); 425} 426 427void UnlinkedEvalCodeBlock::destroy(JSCell* cell) 428{ 429 jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock(); 430} 431 432void UnlinkedFunctionCodeBlock::destroy(JSCell* cell) 433{ 434 jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock(); 435} 436 437void UnlinkedFunctionExecutable::destroy(JSCell* cell) 438{ 439 jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable(); 440} 441 442void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions) 443{ 444 m_unlinkedInstructions = WTF::move(instructions); 445} 446 447const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const 448{ 449 ASSERT(m_unlinkedInstructions.get()); 450 return *m_unlinkedInstructions; 451} 452 453} 454 455