2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "EvalCodeCache.h"
34 #include "Instruction.h"
36 #include "JSGlobalObject.h"
37 #include "JumpTable.h"
41 #include <wtf/RefPtr.h>
42 #include <wtf/Vector.h>
45 #include "StructureStubInfo.h"
52 enum CodeType { GlobalCode, EvalCode, FunctionCode };
54 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
62 MacroAssembler::CodeLocationLabel nativeCode;
67 // The code, and the associated pool from which it was allocated.
73 RefPtr<ExecutablePool> executablePool;
83 JITCodeRef(void* code, PassRefPtr<ExecutablePool> executablePool)
88 , executablePool(executablePool)
94 struct ExpressionRangeInfo {
96 MaxOffset = (1 << 7) - 1,
97 MaxDivot = (1 << 25) - 1
99 uint32_t instructionOffset : 25;
100 uint32_t divotPoint : 25;
101 uint32_t startOffset : 7;
102 uint32_t endOffset : 7;
106 uint32_t instructionOffset;
110 // Both op_construct and op_instanceof require a use of op_get_by_id to get
111 // the prototype property from an object. The exception messages for exceptions
112 // thrown by these instances op_get_by_id need to reflect this.
113 struct GetByIdExceptionInfo {
114 unsigned bytecodeOffset : 31;
115 bool isOpConstruct : 1;
119 struct CallLinkInfo {
125 unsigned bytecodeIndex;
126 MacroAssembler::CodeLocationCall callReturnLocation;
127 MacroAssembler::CodeLocationDataLabelPtr hotPathBegin;
128 MacroAssembler::CodeLocationCall hotPathOther;
129 MacroAssembler::CodeLocationLabel coldPathOther;
133 void setUnlinked() { callee = 0; }
134 bool isLinked() { return callee; }
137 struct FunctionRegisterInfo {
138 FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex)
139 : bytecodeOffset(bytecodeOffset)
140 , functionRegisterIndex(functionRegisterIndex)
144 unsigned bytecodeOffset;
145 int functionRegisterIndex;
148 struct GlobalResolveInfo {
149 GlobalResolveInfo(unsigned bytecodeOffset)
152 , bytecodeOffset(bytecodeOffset)
156 Structure* structure;
158 unsigned bytecodeOffset;
161 // This structure is used to map from a call return location
162 // (given as an offset in bytes into the JIT code) back to
163 // the bytecode index of the corresponding bytecode operation.
164 // This is then used to look up the corresponding handler.
165 struct CallReturnOffsetToBytecodeIndex {
166 CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex)
167 : callReturnOffset(callReturnOffset)
168 , bytecodeIndex(bytecodeIndex)
172 unsigned callReturnOffset;
173 unsigned bytecodeIndex;
176 // valueAtPosition helpers for the binaryChop algorithm below.
178 inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo)
180 return structureStubInfo->callReturnLocation.calleeReturnAddressValue();
183 inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo)
185 return callLinkInfo->callReturnLocation.calleeReturnAddressValue();
188 inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc)
190 return pc->callReturnOffset;
193 // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array,
194 // compares result with key (KeyTypes should be comparable with '--', '<', '>').
195 // Optimized for cases where the array contains the key, checked by assertions.
196 template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)>
197 inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key)
199 // The array must contain at least one element (pre-condition, array does conatin key).
200 // If the array only contains one element, no need to do the comparison.
202 // Pick an element to check, half way through the array, and read the value.
203 int pos = (size - 1) >> 1;
204 KeyType val = valueAtPosition(&array[pos]);
206 // If the key matches, success!
209 // The item we are looking for is smaller than the item being check; reduce the value of 'size',
210 // chopping off the right hand half of the array.
213 // Discard all values in the left hand half of the array, up to and including the item at pos.
219 // 'size' should never reach zero.
223 // If we reach this point we've chopped down to one element, no need to check it matches
225 ASSERT(key == valueAtPosition(&array[0]));
233 CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset);
237 void refStructures(Instruction* vPC) const;
238 void derefStructures(Instruction* vPC) const;
240 void unlinkCallers();
243 static void dumpStatistics();
245 #if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING
246 void dump(ExecState*) const;
247 void printStructures(const Instruction*) const;
248 void printStructure(const char* name, const Instruction*, int operand) const;
251 inline bool isKnownNotImmediate(int index)
253 if (index == m_thisRegister)
256 if (isConstantRegisterIndex(index))
257 return getConstant(index).isCell();
262 ALWAYS_INLINE bool isConstantRegisterIndex(int index)
264 return index >= m_numVars && index < m_numVars + m_numConstants;
267 ALWAYS_INLINE JSValuePtr getConstant(int index)
269 return m_constantRegisters[index - m_numVars].getJSValue();
272 ALWAYS_INLINE bool isTemporaryRegisterIndex(int index)
274 return index >= m_numVars + m_numConstants;
277 HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset);
278 int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset);
279 int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
280 bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&);
283 void addCaller(CallLinkInfo* caller)
285 caller->callee = this;
286 caller->position = m_linkedCallerList.size();
287 m_linkedCallerList.append(caller);
290 void removeCaller(CallLinkInfo* caller)
292 unsigned pos = caller->position;
293 unsigned lastPos = m_linkedCallerList.size() - 1;
295 if (pos != lastPos) {
296 m_linkedCallerList[pos] = m_linkedCallerList[lastPos];
297 m_linkedCallerList[pos]->position = pos;
299 m_linkedCallerList.shrink(lastPos);
302 StructureStubInfo& getStubInfo(void* returnAddress)
304 return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress));
307 CallLinkInfo& getCallLinkInfo(void* returnAddress)
309 return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress));
312 unsigned getBytecodeIndex(CallFrame* callFrame, void* nativePC)
314 reparseForExceptionInfoIfNecessary(callFrame);
315 return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(m_exceptionInfo->m_callReturnIndexVector.begin(), m_exceptionInfo->m_callReturnIndexVector.size(), m_jitCode.code.offsetOf(nativePC))->bytecodeIndex;
318 void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; }
319 bool isNumericCompareFunction() { return m_isNumericCompareFunction; }
321 bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex);
324 Vector<Instruction>& instructions() { return m_instructions; }
326 void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; }
330 void setJITCode(JITCodeRef& jitCode);
331 JITCode jitCode() { return m_jitCode.code; }
332 ExecutablePool* executablePool() { return m_jitCode.executablePool.get(); }
335 ScopeNode* ownerNode() const { return m_ownerNode; }
337 void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; }
339 void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; }
340 int thisRegister() const { return m_thisRegister; }
342 void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; }
343 bool needsFullScopeChain() const { return m_needsFullScopeChain; }
344 void setUsesEval(bool usesEval) { m_usesEval = usesEval; }
345 bool usesEval() const { return m_usesEval; }
346 void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; }
347 bool usesArguments() const { return m_usesArguments; }
349 CodeType codeType() const { return m_codeType; }
351 SourceProvider* source() const { return m_source.get(); }
352 unsigned sourceOffset() const { return m_sourceOffset; }
354 size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
355 void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
356 unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
357 unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
360 void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); }
361 void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); }
362 bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset);
364 size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); }
365 void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); }
366 StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; }
368 void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); }
369 GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
370 bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset);
372 size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); }
373 void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); }
374 CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; }
376 void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); }
379 // Exception handling support
381 size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
382 void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); }
383 HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
385 bool hasExceptionInfo() const { return m_exceptionInfo; }
386 void clearExceptionInfo() { m_exceptionInfo.clear(); }
388 void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); }
389 void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); }
391 size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); }
392 void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); }
393 LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); }
396 Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; }
401 size_t numberOfIdentifiers() const { return m_identifiers.size(); }
402 void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
403 Identifier& identifier(int index) { return m_identifiers[index]; }
405 size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
406 void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); }
407 Register& constantRegister(int index) { return m_constantRegisters[index]; }
409 unsigned addFunctionExpression(FuncExprNode* n) { unsigned size = m_functionExpressions.size(); m_functionExpressions.append(n); return size; }
410 FuncExprNode* functionExpression(int index) const { return m_functionExpressions[index].get(); }
412 unsigned addFunction(FuncDeclNode* n) { createRareDataIfNecessary(); unsigned size = m_rareData->m_functions.size(); m_rareData->m_functions.append(n); return size; }
413 FuncDeclNode* function(int index) const { ASSERT(m_rareData); return m_rareData->m_functions[index].get(); }
415 bool hasFunctions() const { return m_functionExpressions.size() || (m_rareData && m_rareData->m_functions.size()); }
417 unsigned addUnexpectedConstant(JSValuePtr v) { createRareDataIfNecessary(); unsigned size = m_rareData->m_unexpectedConstants.size(); m_rareData->m_unexpectedConstants.append(v); return size; }
418 JSValuePtr unexpectedConstant(int index) const { ASSERT(m_rareData); return m_rareData->m_unexpectedConstants[index]; }
420 unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; }
421 RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); }
426 size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; }
427 SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); }
428 SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; }
430 size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; }
431 SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); }
432 SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; }
434 size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
435 StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
436 StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
439 SymbolTable& symbolTable() { return m_symbolTable; }
441 EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }
445 // FIXME: Make these remaining members private.
447 int m_numCalleeRegisters;
448 // NOTE: numConstants holds the number of constant registers allocated
449 // by the code generator, not the number of constant registers used.
450 // (Duplicate constants are uniqued during code generation, and spare
451 // constant registers may be allocated.)
457 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
458 void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
461 void reparseForExceptionInfoIfNecessary(CallFrame*);
463 void createRareDataIfNecessary()
466 m_rareData.set(new RareData);
469 ScopeNode* m_ownerNode;
470 JSGlobalData* m_globalData;
472 Vector<Instruction> m_instructions;
474 unsigned m_instructionCount;
477 JITCodeRef m_jitCode;
482 bool m_needsFullScopeChain;
484 bool m_usesArguments;
485 bool m_isNumericCompareFunction;
489 RefPtr<SourceProvider> m_source;
490 unsigned m_sourceOffset;
493 Vector<unsigned> m_propertyAccessInstructions;
494 Vector<unsigned> m_globalResolveInstructions;
496 Vector<StructureStubInfo> m_structureStubInfos;
497 Vector<GlobalResolveInfo> m_globalResolveInfos;
498 Vector<CallLinkInfo> m_callLinkInfos;
499 Vector<CallLinkInfo*> m_linkedCallerList;
502 Vector<unsigned> m_jumpTargets;
505 Vector<Identifier> m_identifiers;
506 Vector<Register> m_constantRegisters;
507 Vector<RefPtr<FuncExprNode> > m_functionExpressions;
509 SymbolTable m_symbolTable;
511 struct ExceptionInfo {
512 Vector<ExpressionRangeInfo> m_expressionInfo;
513 Vector<LineInfo> m_lineInfo;
514 Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo;
517 Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector;
520 OwnPtr<ExceptionInfo> m_exceptionInfo;
523 Vector<HandlerInfo> m_exceptionHandlers;
526 Vector<RefPtr<FuncDeclNode> > m_functions;
527 Vector<JSValuePtr> m_unexpectedConstants;
528 Vector<RefPtr<RegExp> > m_regexps;
531 Vector<SimpleJumpTable> m_immediateSwitchJumpTables;
532 Vector<SimpleJumpTable> m_characterSwitchJumpTables;
533 Vector<StringJumpTable> m_stringSwitchJumpTables;
535 EvalCodeCache m_evalCodeCache;
538 Vector<FunctionRegisterInfo> m_functionRegisterInfos;
541 OwnPtr<RareData> m_rareData;
544 // Program code is not marked by any function, so we make the global object
545 // responsible for marking it.
547 class ProgramCodeBlock : public CodeBlock {
549 ProgramCodeBlock(ScopeNode* ownerNode, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider)
550 : CodeBlock(ownerNode, codeType, sourceProvider, 0)
551 , m_globalObject(globalObject)
553 m_globalObject->codeBlocks().add(this);
559 m_globalObject->codeBlocks().remove(this);
562 void clearGlobalObject() { m_globalObject = 0; }
565 JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool.
568 class EvalCodeBlock : public ProgramCodeBlock {
570 EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth)
571 : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider)
572 , m_baseScopeDepth(baseScopeDepth)
576 int baseScopeDepth() const { return m_baseScopeDepth; }
579 int m_baseScopeDepth;
584 #endif // CodeBlock_h