summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp')
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
new file mode 100644
index 000000000..73959cfd9
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2012, 2013, 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "UnlinkedCodeBlock.h"
+
+#include "BytecodeGenerator.h"
+#include "ClassInfo.h"
+#include "CodeCache.h"
+#include "Executable.h"
+#include "ExecutableInfo.h"
+#include "FunctionOverrides.h"
+#include "JSString.h"
+#include "JSCInlines.h"
+#include "Parser.h"
+#include "SourceProvider.h"
+#include "Structure.h"
+#include "SymbolTable.h"
+#include "UnlinkedInstructionStream.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
+const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) };
+const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) };
+const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
+const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
+
+UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info)
+ : Base(*vm, structure)
+ , m_numVars(0)
+ , m_numCalleeRegisters(0)
+ , m_numParameters(0)
+ , m_vm(vm)
+ , m_globalObjectRegister(VirtualRegister())
+ , m_needsFullScopeChain(info.needsActivation())
+ , m_usesEval(info.usesEval())
+ , m_isStrictMode(info.isStrictMode())
+ , m_isConstructor(info.isConstructor())
+ , m_hasCapturedVariables(false)
+ , m_isBuiltinFunction(info.isBuiltinFunction())
+ , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
+ , m_firstLine(0)
+ , m_lineCount(0)
+ , m_endColumn(UINT_MAX)
+ , m_features(0)
+ , m_codeType(codeType)
+ , m_arrayProfileCount(0)
+ , m_arrayAllocationProfileCount(0)
+ , m_objectAllocationProfileCount(0)
+ , m_valueProfileCount(0)
+ , m_llintCallLinkInfoCount(0)
+#if ENABLE(BYTECODE_COMMENTS)
+ , m_bytecodeCommentIterator(0)
+#endif
+{
+ for (auto& constantRegisterIndex : m_linkTimeConstants)
+ constantRegisterIndex = 0;
+ ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
+}
+
+void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_symbolTable);
+ for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr)
+ visitor.append(ptr);
+ for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
+ visitor.append(ptr);
+ visitor.appendValues(thisObject->m_constantRegisters.data(), thisObject->m_constantRegisters.size());
+ if (thisObject->m_rareData) {
+ for (size_t i = 0, end = thisObject->m_rareData->m_regexps.size(); i != end; i++)
+ visitor.append(&thisObject->m_rareData->m_regexps[i]);
+ }
+}
+
+int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
+{
+ ASSERT(bytecodeOffset < instructions().count());
+ int divot;
+ int startOffset;
+ int endOffset;
+ unsigned line;
+ unsigned column;
+ expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
+ return line;
+}
+
+inline void UnlinkedCodeBlock::getLineAndColumn(ExpressionRangeInfo& info,
+ unsigned& line, unsigned& column)
+{
+ switch (info.mode) {
+ case ExpressionRangeInfo::FatLineMode:
+ info.decodeFatLineMode(line, column);
+ break;
+ case ExpressionRangeInfo::FatColumnMode:
+ info.decodeFatColumnMode(line, column);
+ break;
+ case ExpressionRangeInfo::FatLineAndColumnMode: {
+ unsigned fatIndex = info.position;
+ ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex];
+ line = fatPos.line;
+ column = fatPos.column;
+ break;
+ }
+ } // switch
+}
+
+#ifndef NDEBUG
+static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column)
+{
+ const auto& instructions = instructionStream.unpackForDebugging();
+ OpcodeID opcode = instructions[instructionOffset].u.opcode;
+ const char* event = "";
+ if (opcode == op_debug) {
+ switch (instructions[instructionOffset + 1].u.operand) {
+ case WillExecuteProgram: event = " WillExecuteProgram"; break;
+ case DidExecuteProgram: event = " DidExecuteProgram"; break;
+ case DidEnterCallFrame: event = " DidEnterCallFrame"; break;
+ case DidReachBreakpoint: event = " DidReachBreakpoint"; break;
+ case WillLeaveCallFrame: event = " WillLeaveCallFrame"; break;
+ case WillExecuteStatement: event = " WillExecuteStatement"; break;
+ }
+ }
+ dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event);
+}
+
+void UnlinkedCodeBlock::dumpExpressionRangeInfo()
+{
+ Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
+
+ size_t size = m_expressionInfo.size();
+ dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size);
+ for (size_t i = 0; i < size; i++) {
+ ExpressionRangeInfo& info = expressionInfo[i];
+ unsigned line;
+ unsigned column;
+ getLineAndColumn(info, line, column);
+ dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column);
+ }
+ dataLog("}\n");
+}
+#endif
+
+void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset,
+ int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
+{
+ ASSERT(bytecodeOffset < instructions().count());
+
+ if (!m_expressionInfo.size()) {
+ startOffset = 0;
+ endOffset = 0;
+ divot = 0;
+ line = 0;
+ column = 0;
+ return;
+ }
+
+ Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
+
+ int low = 0;
+ int high = expressionInfo.size();
+ while (low < high) {
+ int mid = low + (high - low) / 2;
+ if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+ if (!low)
+ low = 1;
+
+ ExpressionRangeInfo& info = expressionInfo[low - 1];
+ startOffset = info.startOffset;
+ endOffset = info.endOffset;
+ divot = info.divotPoint;
+ getLineAndColumn(info, line, column);
+}
+
+void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset,
+ int divot, int startOffset, int endOffset, unsigned line, unsigned column)
+{
+ if (divot > ExpressionRangeInfo::MaxDivot) {
+ // Overflow has occurred, we can only give line number info for errors for this region
+ divot = 0;
+ startOffset = 0;
+ endOffset = 0;
+ } else if (startOffset > ExpressionRangeInfo::MaxOffset) {
+ // If the start offset is out of bounds we clear both offsets
+ // so we only get the divot marker. Error message will have to be reduced
+ // to line and charPosition number.
+ startOffset = 0;
+ endOffset = 0;
+ } else if (endOffset > ExpressionRangeInfo::MaxOffset) {
+ // The end offset is only used for additional context, and is much more likely
+ // to overflow (eg. function call arguments) so we are willing to drop it without
+ // dropping the rest of the range.
+ endOffset = 0;
+ }
+
+ unsigned positionMode =
+ (line <= ExpressionRangeInfo::MaxFatLineModeLine && column <= ExpressionRangeInfo::MaxFatLineModeColumn)
+ ? ExpressionRangeInfo::FatLineMode
+ : (line <= ExpressionRangeInfo::MaxFatColumnModeLine && column <= ExpressionRangeInfo::MaxFatColumnModeColumn)
+ ? ExpressionRangeInfo::FatColumnMode
+ : ExpressionRangeInfo::FatLineAndColumnMode;
+
+ ExpressionRangeInfo info;
+ info.instructionOffset = instructionOffset;
+ info.divotPoint = divot;
+ info.startOffset = startOffset;
+ info.endOffset = endOffset;
+
+ info.mode = positionMode;
+ switch (positionMode) {
+ case ExpressionRangeInfo::FatLineMode:
+ info.encodeFatLineMode(line, column);
+ break;
+ case ExpressionRangeInfo::FatColumnMode:
+ info.encodeFatColumnMode(line, column);
+ break;
+ case ExpressionRangeInfo::FatLineAndColumnMode: {
+ createRareDataIfNecessary();
+ unsigned fatIndex = m_rareData->m_expressionInfoFatPositions.size();
+ ExpressionRangeInfo::FatPosition fatPos = { line, column };
+ m_rareData->m_expressionInfoFatPositions.append(fatPos);
+ info.position = fatIndex;
+ }
+ } // switch
+
+ m_expressionInfo.append(info);
+}
+
+bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot)
+{
+ static const bool verbose = false;
+ auto iter = m_typeProfilerInfoMap.find(bytecodeOffset);
+ if (iter == m_typeProfilerInfoMap.end()) {
+ if (verbose)
+ dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
+ startDivot = UINT_MAX;
+ endDivot = UINT_MAX;
+ return false;
+ }
+
+ TypeProfilerExpressionRange& range = iter->value;
+ startDivot = range.m_startDivot;
+ endDivot = range.m_endDivot;
+ return true;
+}
+
+void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot)
+{
+ TypeProfilerExpressionRange range;
+ range.m_startDivot = startDivot;
+ range.m_endDivot = endDivot;
+ m_typeProfilerInfoMap.set(instructionOffset, range);
+}
+
+void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ UnlinkedProgramCodeBlock* thisObject = jsCast<UnlinkedProgramCodeBlock*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+}
+
+UnlinkedCodeBlock::~UnlinkedCodeBlock()
+{
+}
+
+void UnlinkedProgramCodeBlock::destroy(JSCell* cell)
+{
+ jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock();
+}
+
+void UnlinkedEvalCodeBlock::destroy(JSCell* cell)
+{
+ jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock();
+}
+
+void UnlinkedFunctionCodeBlock::destroy(JSCell* cell)
+{
+ jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock();
+}
+
+void UnlinkedFunctionExecutable::destroy(JSCell* cell)
+{
+ jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable();
+}
+
+void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions)
+{
+ m_unlinkedInstructions = WTF::move(instructions);
+}
+
+const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const
+{
+ ASSERT(m_unlinkedInstructions.get());
+ return *m_unlinkedInstructions;
+}
+
+}
+