source: webkit/trunk/JavaScriptCore/bytecode/CodeBlock.h@ 39577

Last change on this file since 39577 was 39577, checked in by [email protected], 16 years ago

2009-01-03 Sam Weinig <[email protected]>

Reviewed by Oliver Hunt.

Change the pcVector from storing native code pointers to storing offsets
from the base pointer. This will allow us to generate the pcVector on demand
for exceptions.

  • bytecode/CodeBlock.h: (JSC::PC::PC): (JSC::getNativePCOffset): (JSC::CodeBlock::getBytecodeIndex):
  • jit/JIT.cpp: (JSC::JIT::privateCompile):
File size: 20.8 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
17 *
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.
28 */
29
30#ifndef CodeBlock_h
31#define CodeBlock_h
32
33#include "EvalCodeCache.h"
34#include "Instruction.h"
35#include "JSGlobalObject.h"
36#include "JumpTable.h"
37#include "Nodes.h"
38#include "RegExp.h"
39#include "UString.h"
40#include <wtf/RefPtr.h>
41#include <wtf/Vector.h>
42
43#if ENABLE(JIT)
44#include "StructureStubInfo.h"
45#endif
46
47namespace JSC {
48
49 class ExecState;
50
51 enum CodeType { GlobalCode, EvalCode, FunctionCode };
52
53 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
54
55 struct HandlerInfo {
56 uint32_t start;
57 uint32_t end;
58 uint32_t target;
59 uint32_t scopeDepth;
60#if ENABLE(JIT)
61 void* nativeCode;
62#endif
63 };
64
65#if ENABLE(JIT)
66 // The code, and the associated pool from which it was allocated.
67 struct JITCodeRef {
68 void* code;
69 RefPtr<ExecutablePool> executablePool;
70
71 JITCodeRef()
72 : code(0)
73 {
74 }
75
76 JITCodeRef(void* code, PassRefPtr<ExecutablePool> executablePool)
77 : code(code)
78 , executablePool(executablePool)
79 {
80 }
81 };
82#endif
83
84 struct ExpressionRangeInfo {
85 enum {
86 MaxOffset = (1 << 7) - 1,
87 MaxDivot = (1 << 25) - 1
88 };
89 uint32_t instructionOffset : 25;
90 uint32_t divotPoint : 25;
91 uint32_t startOffset : 7;
92 uint32_t endOffset : 7;
93 };
94
95 struct LineInfo {
96 uint32_t instructionOffset;
97 int32_t lineNumber;
98 };
99
100 // Both op_construct and op_instanceof require a use of op_get_by_id to get
101 // the prototype property from an object. The exception messages for exceptions
102 // thrown by these instances op_get_by_id need to reflect this.
103 struct GetByIdExceptionInfo {
104 unsigned bytecodeOffset : 31;
105 bool isOpConstruct : 1;
106 };
107
108#if ENABLE(JIT)
109 struct CallLinkInfo {
110 CallLinkInfo()
111 : callReturnLocation(0)
112 , hotPathBegin(0)
113 , hotPathOther(0)
114 , coldPathOther(0)
115 , callee(0)
116 {
117 }
118
119 unsigned bytecodeIndex;
120 void* callReturnLocation;
121 void* hotPathBegin;
122 void* hotPathOther;
123 void* coldPathOther;
124 CodeBlock* callee;
125 unsigned position;
126
127 void setUnlinked() { callee = 0; }
128 bool isLinked() { return callee; }
129 };
130
131 struct FunctionRegisterInfo {
132 FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex)
133 : bytecodeOffset(bytecodeOffset)
134 , functionRegisterIndex(functionRegisterIndex)
135 {
136 }
137
138 unsigned bytecodeOffset;
139 int functionRegisterIndex;
140 };
141
142 struct GlobalResolveInfo {
143 GlobalResolveInfo()
144 : structure(0)
145 , offset(0)
146 {
147 }
148
149 Structure* structure;
150 unsigned offset;
151 };
152
153 struct PC {
154 PC(ptrdiff_t nativePCOffset, unsigned bytecodeIndex)
155 : nativePCOffset(nativePCOffset)
156 , bytecodeIndex(bytecodeIndex)
157 {
158 }
159
160 ptrdiff_t nativePCOffset;
161 unsigned bytecodeIndex;
162 };
163
164 // valueAtPosition helpers for the binaryChop algorithm below.
165
166 inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo)
167 {
168 return structureStubInfo->callReturnLocation;
169 }
170
171 inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo)
172 {
173 return callLinkInfo->callReturnLocation;
174 }
175
176 inline ptrdiff_t getNativePCOffset(PC* pc)
177 {
178 return pc->nativePCOffset;
179 }
180
181 // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array,
182 // compares result with key (KeyTypes should be comparable with '--', '<', '>').
183 // Optimized for cases where the array contains the key, checked by assertions.
184 template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)>
185 inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key)
186 {
187 // The array must contain at least one element (pre-condition, array does conatin key).
188 // If the array only contains one element, no need to do the comparison.
189 while (size > 1) {
190 // Pick an element to check, half way through the array, and read the value.
191 int pos = (size - 1) >> 1;
192 KeyType val = valueAtPosition(&array[pos]);
193
194 // If the key matches, success!
195 if (val == key)
196 return &array[pos];
197 // The item we are looking for is smaller than the item being check; reduce the value of 'size',
198 // chopping off the right hand half of the array.
199 else if (key < val)
200 size = pos;
201 // Discard all values in the left hand half of the array, up to and including the item at pos.
202 else {
203 size -= (pos + 1);
204 array += (pos + 1);
205 }
206
207 // 'size' should never reach zero.
208 ASSERT(size);
209 }
210
211 // If we reach this point we've chopped down to one element, no need to check it matches
212 ASSERT(size == 1);
213 ASSERT(key == valueAtPosition(&array[0]));
214 return &array[0];
215 }
216#endif
217
218 class CodeBlock {
219 friend class JIT;
220 public:
221 CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset);
222 ~CodeBlock();
223
224 void mark();
225 void refStructures(Instruction* vPC) const;
226 void derefStructures(Instruction* vPC) const;
227#if ENABLE(JIT)
228 void unlinkCallers();
229#endif
230
231 static void dumpStatistics();
232
233#if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING
234 void dump(ExecState*) const;
235 void printStructures(const Instruction*) const;
236 void printStructure(const char* name, const Instruction*, int operand) const;
237#endif
238
239 inline bool isKnownNotImmediate(int index)
240 {
241 if (index == m_thisRegister)
242 return true;
243
244 if (isConstantRegisterIndex(index))
245 return !JSImmediate::isImmediate(getConstant(index));
246
247 return false;
248 }
249
250 ALWAYS_INLINE bool isConstantRegisterIndex(int index)
251 {
252 return index >= m_numVars && index < m_numVars + m_numConstants;
253 }
254
255 ALWAYS_INLINE JSValue* getConstant(int index)
256 {
257 return m_constantRegisters[index - m_numVars].getJSValue();
258 }
259
260 ALWAYS_INLINE bool isTemporaryRegisterIndex(int index)
261 {
262 return index >= m_numVars + m_numConstants;
263 }
264
265 HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset);
266 int lineNumberForBytecodeOffset(unsigned bytecodeOffset);
267 int expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
268 bool getByIdExceptionInfoForBytecodeOffset(unsigned bytecodeOffset, OpcodeID&);
269
270#if ENABLE(JIT)
271 void addCaller(CallLinkInfo* caller)
272 {
273 caller->callee = this;
274 caller->position = m_linkedCallerList.size();
275 m_linkedCallerList.append(caller);
276 }
277
278 void removeCaller(CallLinkInfo* caller)
279 {
280 unsigned pos = caller->position;
281 unsigned lastPos = m_linkedCallerList.size() - 1;
282
283 if (pos != lastPos) {
284 m_linkedCallerList[pos] = m_linkedCallerList[lastPos];
285 m_linkedCallerList[pos]->position = pos;
286 }
287 m_linkedCallerList.shrink(lastPos);
288 }
289
290 StructureStubInfo& getStubInfo(void* returnAddress)
291 {
292 return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress));
293 }
294
295 CallLinkInfo& getCallLinkInfo(void* returnAddress)
296 {
297 return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress));
298 }
299
300 unsigned getBytecodeIndex(void* nativePC)
301 {
302 ptrdiff_t nativePCOffset = reinterpret_cast<void**>(nativePC) - reinterpret_cast<void**>(m_jitCode.code);
303 return binaryChop<PC, ptrdiff_t, getNativePCOffset>(m_pcVector.begin(), m_pcVector.size(), nativePCOffset)->bytecodeIndex;
304 }
305
306 bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex);
307#endif
308
309 Vector<Instruction>& instructions() { return m_instructions; }
310#ifndef NDEBUG
311 void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; }
312#endif
313
314#if ENABLE(JIT)
315 void setJITCode(JITCodeRef& jitCode);
316 void* jitCode() { return m_jitCode.code; }
317 ExecutablePool* executablePool() { return m_jitCode.executablePool.get(); }
318#endif
319
320 ScopeNode* ownerNode() const { return m_ownerNode; }
321
322 void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; }
323
324 void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; }
325 int thisRegister() const { return m_thisRegister; }
326
327 void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; }
328 bool needsFullScopeChain() const { return m_needsFullScopeChain; }
329 void setUsesEval(bool usesEval) { m_usesEval = usesEval; }
330 bool usesEval() const { return m_usesEval; }
331 void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; }
332 bool usesArguments() const { return m_usesArguments; }
333
334 CodeType codeType() const { return m_codeType; }
335
336 SourceProvider* source() const { return m_source.get(); }
337 unsigned sourceOffset() const { return m_sourceOffset; }
338
339 size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
340 void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
341 unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
342 unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
343
344 size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
345 void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); }
346 HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
347
348 void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { return m_expressionInfo.append(expressionInfo); }
349 void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { m_getByIdExceptionInfo.append(info); }
350
351 size_t numberOfLineInfos() const { return m_lineInfo.size(); }
352 void addLineInfo(const LineInfo& lineInfo) { return m_lineInfo.append(lineInfo); }
353 LineInfo& lastLineInfo() { return m_lineInfo.last(); }
354
355#if !ENABLE(JIT)
356 void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); }
357 void addGlobalResolveInstruction(unsigned globalResolveInstructions) { m_globalResolveInstructions.append(globalResolveInstructions); }
358#else
359 size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); }
360 void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); }
361 StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; }
362
363 void addGlobalResolveInfo() { m_globalResolveInfos.append(GlobalResolveInfo()); }
364 GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
365
366 size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); }
367 void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); }
368 CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; }
369
370 void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); }
371
372 Vector<PC>& pcVector() { return m_pcVector; }
373#endif
374
375 // Constant Pool
376
377 size_t numberOfIdentifiers() const { return m_identifiers.size(); }
378 void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
379 Identifier& identifier(int index) { return m_identifiers[index]; }
380
381 size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
382 void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); }
383 Register& constantRegister(int index) { return m_constantRegisters[index]; }
384
385 unsigned addFunctionExpression(FuncExprNode* n) { unsigned size = m_functionExpressions.size(); m_functionExpressions.append(n); return size; }
386 FuncExprNode* functionExpression(int index) const { return m_functionExpressions[index].get(); }
387
388 unsigned addFunction(FuncDeclNode* n) { createRareDataIfNecessary(); unsigned size = m_rareData->m_functions.size(); m_rareData->m_functions.append(n); return size; }
389 FuncDeclNode* function(int index) const { ASSERT(m_rareData); return m_rareData->m_functions[index].get(); }
390
391 unsigned addUnexpectedConstant(JSValue* v) { createRareDataIfNecessary(); unsigned size = m_rareData->m_unexpectedConstants.size(); m_rareData->m_unexpectedConstants.append(v); return size; }
392 JSValue* unexpectedConstant(int index) const { ASSERT(m_rareData); return m_rareData->m_unexpectedConstants[index]; }
393
394 unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; }
395 RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); }
396
397
398 // Jump Tables
399
400 size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; }
401 SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); }
402 SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; }
403
404 size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; }
405 SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); }
406 SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; }
407
408 size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
409 StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
410 StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
411
412
413 SymbolTable& symbolTable() { return m_symbolTable; }
414
415 EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }
416
417 void shrinkToFit();
418
419 // FIXME: Make these remaining members private.
420
421 int m_numCalleeRegisters;
422 // NOTE: numConstants holds the number of constant registers allocated
423 // by the code generator, not the number of constant registers used.
424 // (Duplicate constants are uniqued during code generation, and spare
425 // constant registers may be allocated.)
426 int m_numConstants;
427 int m_numVars;
428 int m_numParameters;
429
430 private:
431#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
432 void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
433#endif
434
435 void createRareDataIfNecessary()
436 {
437 if (!m_rareData)
438 m_rareData.set(new RareData);
439 }
440
441
442 ScopeNode* m_ownerNode;
443 JSGlobalData* m_globalData;
444
445 Vector<Instruction> m_instructions;
446#ifndef NDEBUG
447 unsigned m_instructionCount;
448#endif
449#if ENABLE(JIT)
450 JITCodeRef m_jitCode;
451#endif
452
453 int m_thisRegister;
454
455 bool m_needsFullScopeChain;
456 bool m_usesEval;
457 bool m_usesArguments;
458
459 CodeType m_codeType;
460
461 RefPtr<SourceProvider> m_source;
462 unsigned m_sourceOffset;
463
464#if !ENABLE(JIT)
465 Vector<unsigned> m_propertyAccessInstructions;
466 Vector<unsigned> m_globalResolveInstructions;
467#else
468 Vector<StructureStubInfo> m_structureStubInfos;
469 Vector<GlobalResolveInfo> m_globalResolveInfos;
470 Vector<CallLinkInfo> m_callLinkInfos;
471 Vector<CallLinkInfo*> m_linkedCallerList;
472#endif
473
474 Vector<unsigned> m_jumpTargets;
475
476 Vector<ExpressionRangeInfo> m_expressionInfo;
477 Vector<LineInfo> m_lineInfo;
478 Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo;
479
480#if ENABLE(JIT)
481 Vector<PC> m_pcVector;
482#endif
483
484 // Constant Pool
485 Vector<Identifier> m_identifiers;
486 Vector<Register> m_constantRegisters;
487 Vector<RefPtr<FuncExprNode> > m_functionExpressions;
488
489 SymbolTable m_symbolTable;
490
491 struct RareData {
492 Vector<HandlerInfo> m_exceptionHandlers;
493
494 // Rare Constants
495 Vector<RefPtr<FuncDeclNode> > m_functions;
496 Vector<JSValue*> m_unexpectedConstants;
497 Vector<RefPtr<RegExp> > m_regexps;
498
499 // Jump Tables
500 Vector<SimpleJumpTable> m_immediateSwitchJumpTables;
501 Vector<SimpleJumpTable> m_characterSwitchJumpTables;
502 Vector<StringJumpTable> m_stringSwitchJumpTables;
503
504 EvalCodeCache m_evalCodeCache;
505
506#if ENABLE(JIT)
507 Vector<FunctionRegisterInfo> m_functionRegisterInfos;
508#endif
509 };
510
511 OwnPtr<RareData> m_rareData;
512 };
513
514 // Program code is not marked by any function, so we make the global object
515 // responsible for marking it.
516
517 class ProgramCodeBlock : public CodeBlock {
518 public:
519 ProgramCodeBlock(ScopeNode* ownerNode, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider)
520 : CodeBlock(ownerNode, codeType, sourceProvider, 0)
521 , m_globalObject(globalObject)
522 {
523 m_globalObject->codeBlocks().add(this);
524 }
525
526 ~ProgramCodeBlock()
527 {
528 if (m_globalObject)
529 m_globalObject->codeBlocks().remove(this);
530 }
531
532 void clearGlobalObject() { m_globalObject = 0; }
533
534 private:
535 JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool.
536 };
537
538 class EvalCodeBlock : public ProgramCodeBlock {
539 public:
540 EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider)
541 : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider)
542 {
543 }
544 };
545
546} // namespace JSC
547
548#endif // CodeBlock_h
Note: See TracBrowser for help on using the repository browser.