|
Lines 1-5
Source/JavaScriptCore/runtime/SymbolTable.h_sec1
|
| 1 |
/* |
1 |
/* |
| 2 |
* Copyright (C) 2007, 2008, 2012-2014 Apple Inc. All rights reserved. |
2 |
* Copyright (C) 2007, 2008, 2012-2015 Apple Inc. All rights reserved. |
| 3 |
* |
3 |
* |
| 4 |
* Redistribution and use in source and binary forms, with or without |
4 |
* Redistribution and use in source and binary forms, with or without |
| 5 |
* modification, are permitted provided that the following conditions |
5 |
* modification, are permitted provided that the following conditions |
|
Lines 31-36
Source/JavaScriptCore/runtime/SymbolTable.h_sec2
|
| 31 |
|
31 |
|
| 32 |
#include "ConcurrentJITLock.h" |
32 |
#include "ConcurrentJITLock.h" |
| 33 |
#include "JSObject.h" |
33 |
#include "JSObject.h" |
|
|
34 |
#include "ScopedArgumentsTable.h" |
| 34 |
#include "TypeLocation.h" |
35 |
#include "TypeLocation.h" |
| 35 |
#include "VariableWatchpointSet.h" |
36 |
#include "VariableWatchpointSet.h" |
| 36 |
#include <memory> |
37 |
#include <memory> |
|
Lines 39-62
Source/JavaScriptCore/runtime/SymbolTable.h_sec3
|
| 39 |
|
40 |
|
| 40 |
namespace JSC { |
41 |
namespace JSC { |
| 41 |
|
42 |
|
| 42 |
struct SlowArgument { |
|
|
| 43 |
public: |
| 44 |
enum Status { |
| 45 |
Normal = 0, |
| 46 |
Captured = 1, |
| 47 |
Deleted = 2 |
| 48 |
}; |
| 49 |
|
| 50 |
SlowArgument() |
| 51 |
: status(Normal) |
| 52 |
, index(0) |
| 53 |
{ |
| 54 |
} |
| 55 |
|
| 56 |
Status status; |
| 57 |
int index; // If status is 'Deleted', index is bogus. |
| 58 |
}; |
| 59 |
|
| 60 |
static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } |
43 |
static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } |
| 61 |
|
44 |
|
| 62 |
// The bit twiddling in this class assumes that every register index is a |
45 |
// The bit twiddling in this class assumes that every register index is a |
|
Lines 86-91
static ALWAYS_INLINE int missingSymbolMa
Source/JavaScriptCore/runtime/SymbolTable.h_sec4
|
| 86 |
// copy: SymbolTableEntry --> FatEntry -----^ |
69 |
// copy: SymbolTableEntry --> FatEntry -----^ |
| 87 |
|
70 |
|
| 88 |
struct SymbolTableEntry { |
71 |
struct SymbolTableEntry { |
|
|
72 |
private: |
| 73 |
static VarOffset varOffsetFromBits(intptr_t bits) |
| 74 |
{ |
| 75 |
VarKind kind; |
| 76 |
if (bits & StackFlag) |
| 77 |
kind = StackVarKind; |
| 78 |
else if (bits & CapturedArgumentFlag) |
| 79 |
kind = CapturedArgumentKind; |
| 80 |
else |
| 81 |
kind = ScopeVarKind; |
| 82 |
return VarOffset::assemble(kind, static_cast<int>(bits >> FlagBits)); |
| 83 |
} |
| 84 |
|
| 85 |
static ScopeOffset scopeOffsetFromBits(intptr_t bits) |
| 86 |
{ |
| 87 |
ASSERT(!(bits & StackFlag)); |
| 88 |
ASSERT(!(bits & CapturedArgumentFlag)); |
| 89 |
return ScopeOffset(static_cast<int>(bits >> FlagBits)); |
| 90 |
} |
| 91 |
|
| 92 |
public: |
| 93 |
|
| 89 |
// Use the SymbolTableEntry::Fast class, either via implicit cast or by calling |
94 |
// Use the SymbolTableEntry::Fast class, either via implicit cast or by calling |
| 90 |
// getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), |
95 |
// getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), |
| 91 |
// and (2) you are in a hot path where you need to minimize the number of times |
96 |
// and (2) you are in a hot path where you need to minimize the number of times |
|
Lines 107-117
struct SymbolTableEntry {
Source/JavaScriptCore/runtime/SymbolTable.h_sec5
|
| 107 |
return !(m_bits & ~SlimFlag); |
112 |
return !(m_bits & ~SlimFlag); |
| 108 |
} |
113 |
} |
| 109 |
|
114 |
|
| 110 |
int getIndex() const |
115 |
VarOffset varOffset() const |
| 111 |
{ |
116 |
{ |
| 112 |
return static_cast<int>(m_bits >> FlagBits); |
117 |
return varOffsetFromBits(m_bits); |
| 113 |
} |
118 |
} |
| 114 |
|
119 |
|
|
|
120 |
// Asserts if the offset is anything but a scope offset. This structures the assertions |
| 121 |
// in a way that may result in better code, even in release, than doing |
| 122 |
// varOffset().scopeOffset(). |
| 123 |
ScopeOffset scopeOffset() const |
| 124 |
{ |
| 125 |
return scopeOffsetFromBits(m_bits); |
| 126 |
} |
| 127 |
|
| 115 |
bool isReadOnly() const |
128 |
bool isReadOnly() const |
| 116 |
{ |
129 |
{ |
| 117 |
return m_bits & ReadOnlyFlag; |
130 |
return m_bits & ReadOnlyFlag; |
|
Lines 142-159
struct SymbolTableEntry {
Source/JavaScriptCore/runtime/SymbolTable.h_sec6
|
| 142 |
{ |
155 |
{ |
| 143 |
} |
156 |
} |
| 144 |
|
157 |
|
| 145 |
SymbolTableEntry(int index) |
158 |
SymbolTableEntry(VarOffset offset) |
| 146 |
: m_bits(SlimFlag) |
159 |
: m_bits(SlimFlag) |
| 147 |
{ |
160 |
{ |
| 148 |
ASSERT(isValidIndex(index)); |
161 |
ASSERT(isValidVarOffset(offset)); |
| 149 |
pack(index, false, false); |
162 |
pack(offset, false, false); |
| 150 |
} |
163 |
} |
| 151 |
|
164 |
|
| 152 |
SymbolTableEntry(int index, unsigned attributes) |
165 |
SymbolTableEntry(VarOffset offset, unsigned attributes) |
| 153 |
: m_bits(SlimFlag) |
166 |
: m_bits(SlimFlag) |
| 154 |
{ |
167 |
{ |
| 155 |
ASSERT(isValidIndex(index)); |
168 |
ASSERT(isValidVarOffset(offset)); |
| 156 |
pack(index, attributes & ReadOnly, attributes & DontEnum); |
169 |
pack(offset, attributes & ReadOnly, attributes & DontEnum); |
| 157 |
} |
170 |
} |
| 158 |
|
171 |
|
| 159 |
~SymbolTableEntry() |
172 |
~SymbolTableEntry() |
|
Lines 181-189
struct SymbolTableEntry {
Source/JavaScriptCore/runtime/SymbolTable.h_sec7
|
| 181 |
return !(bits() & ~SlimFlag); |
194 |
return !(bits() & ~SlimFlag); |
| 182 |
} |
195 |
} |
| 183 |
|
196 |
|
| 184 |
int getIndex() const |
197 |
VarOffset varOffset() const |
|
|
198 |
{ |
| 199 |
return varOffsetFromBits(bits()); |
| 200 |
} |
| 201 |
|
| 202 |
// Asserts if the offset is anything but a scope offset. This structures the assertions |
| 203 |
// in a way that may result in better code, even in release, than doing |
| 204 |
// varOffset().scopeOffset(). |
| 205 |
ScopeOffset scopeOffset() const |
| 185 |
{ |
206 |
{ |
| 186 |
return static_cast<int>(bits() >> FlagBits); |
207 |
return scopeOffsetFromBits(bits()); |
| 187 |
} |
208 |
} |
| 188 |
|
209 |
|
| 189 |
ALWAYS_INLINE Fast getFast() const |
210 |
ALWAYS_INLINE Fast getFast() const |
|
Lines 209-215
struct SymbolTableEntry {
Source/JavaScriptCore/runtime/SymbolTable.h_sec8
|
| 209 |
|
230 |
|
| 210 |
void setAttributes(unsigned attributes) |
231 |
void setAttributes(unsigned attributes) |
| 211 |
{ |
232 |
{ |
| 212 |
pack(getIndex(), attributes & ReadOnly, attributes & DontEnum); |
233 |
pack(varOffset(), attributes & ReadOnly, attributes & DontEnum); |
| 213 |
} |
234 |
} |
| 214 |
|
235 |
|
| 215 |
bool isReadOnly() const |
236 |
bool isReadOnly() const |
|
Lines 242-248
private:
Source/JavaScriptCore/runtime/SymbolTable.h_sec9
|
| 242 |
static const intptr_t ReadOnlyFlag = 0x2; |
263 |
static const intptr_t ReadOnlyFlag = 0x2; |
| 243 |
static const intptr_t DontEnumFlag = 0x4; |
264 |
static const intptr_t DontEnumFlag = 0x4; |
| 244 |
static const intptr_t NotNullFlag = 0x8; |
265 |
static const intptr_t NotNullFlag = 0x8; |
| 245 |
static const intptr_t FlagBits = 4; |
266 |
static const intptr_t StackFlag = 0x10; |
|
|
267 |
static const intptr_t CapturedArgumentFlag = 0x20; |
| 268 |
static const intptr_t FlagBits = 6; |
| 246 |
|
269 |
|
| 247 |
class FatEntry { |
270 |
class FatEntry { |
| 248 |
WTF_MAKE_FAST_ALLOCATED; |
271 |
WTF_MAKE_FAST_ALLOCATED; |
|
Lines 309-328
private:
Source/JavaScriptCore/runtime/SymbolTable.h_sec10
|
| 309 |
|
332 |
|
| 310 |
JS_EXPORT_PRIVATE void freeFatEntrySlow(); |
333 |
JS_EXPORT_PRIVATE void freeFatEntrySlow(); |
| 311 |
|
334 |
|
| 312 |
void pack(int index, bool readOnly, bool dontEnum) |
335 |
void pack(VarOffset offset, bool readOnly, bool dontEnum) |
| 313 |
{ |
336 |
{ |
| 314 |
ASSERT(!isFat()); |
337 |
ASSERT(!isFat()); |
| 315 |
intptr_t& bitsRef = bits(); |
338 |
intptr_t& bitsRef = bits(); |
| 316 |
bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag | SlimFlag; |
339 |
bitsRef = |
|
|
340 |
(static_cast<intptr_t>(offset.rawOffset()) << FlagBits) | NotNullFlag | SlimFlag; |
| 317 |
if (readOnly) |
341 |
if (readOnly) |
| 318 |
bitsRef |= ReadOnlyFlag; |
342 |
bitsRef |= ReadOnlyFlag; |
| 319 |
if (dontEnum) |
343 |
if (dontEnum) |
| 320 |
bitsRef |= DontEnumFlag; |
344 |
bitsRef |= DontEnumFlag; |
|
|
345 |
switch (offset.kind()) { |
| 346 |
case ScopeVarKind: |
| 347 |
break; |
| 348 |
case StackVarKind: |
| 349 |
bitsRef |= StackFlag; |
| 350 |
break; |
| 351 |
case CapturedArgumentKind: |
| 352 |
bitsRef |= CapturedArgumentFlag; |
| 353 |
break; |
| 354 |
default: |
| 355 |
RELEASE_ASSERT_NOT_REACHED(); |
| 356 |
break; |
| 357 |
} |
| 321 |
} |
358 |
} |
| 322 |
|
359 |
|
| 323 |
bool isValidIndex(int index) |
360 |
static bool isValidVarOffset(VarOffset offset) |
| 324 |
{ |
361 |
{ |
| 325 |
return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); |
362 |
return ((static_cast<intptr_t>(offset.rawOffset()) << FlagBits) >> FlagBits) == static_cast<intptr_t>(offset.rawOffset()); |
| 326 |
} |
363 |
} |
| 327 |
|
364 |
|
| 328 |
intptr_t m_bits; |
365 |
intptr_t m_bits; |
|
Lines 351-357
public:
Source/JavaScriptCore/runtime/SymbolTable.h_sec11
|
| 351 |
static SymbolTable* createNameScopeTable(VM& vm, const Identifier& ident, unsigned attributes) |
388 |
static SymbolTable* createNameScopeTable(VM& vm, const Identifier& ident, unsigned attributes) |
| 352 |
{ |
389 |
{ |
| 353 |
SymbolTable* result = create(vm); |
390 |
SymbolTable* result = create(vm); |
| 354 |
result->add(ident.impl(), SymbolTableEntry(-1, attributes)); |
391 |
result->add(ident.impl(), SymbolTableEntry(VarOffset(ScopeOffset(0)), attributes)); |
| 355 |
return result; |
392 |
return result; |
| 356 |
} |
393 |
} |
| 357 |
|
394 |
|
|
Lines 423-430
public:
Source/JavaScriptCore/runtime/SymbolTable.h_sec12
|
| 423 |
return size(locker); |
460 |
return size(locker); |
| 424 |
} |
461 |
} |
| 425 |
|
462 |
|
|
|
463 |
ScopeOffset maxScopeOffset() const |
| 464 |
{ |
| 465 |
return m_maxScopeOffset; |
| 466 |
} |
| 467 |
|
| 468 |
unsigned scopeSize() const |
| 469 |
{ |
| 470 |
ScopeOffset maxScopeOffset = this->maxScopeOffset(); |
| 471 |
|
| 472 |
// Do some calculation that relies on invalid scope offset plus one being zero. |
| 473 |
unsigned fastResult = maxScopeOffset.offsetUnchecked() + 1; |
| 474 |
|
| 475 |
// Assert that this works. |
| 476 |
ASSERT(fastResult == (!maxScopeOffset ? 0 : maxScopeOffset.offset() + 1)); |
| 477 |
|
| 478 |
return fastResult; |
| 479 |
} |
| 480 |
|
| 426 |
Map::AddResult add(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry) |
481 |
Map::AddResult add(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry) |
| 427 |
{ |
482 |
{ |
|
|
483 |
if (entry.varOffset().isScope() |
| 484 |
&& (!m_maxScopeOffset || m_maxScopeOffset < entry.scopeOffset())) |
| 485 |
m_maxScopeOffset = entry.scopeOffset(); |
| 428 |
return m_map.add(key, entry); |
486 |
return m_map.add(key, entry); |
| 429 |
} |
487 |
} |
| 430 |
|
488 |
|
|
Lines 456-461
public:
Source/JavaScriptCore/runtime/SymbolTable.h_sec13
|
| 456 |
return contains(locker, key); |
514 |
return contains(locker, key); |
| 457 |
} |
515 |
} |
| 458 |
|
516 |
|
|
|
517 |
// The principle behind ScopedArgumentsTable modifications is that we will create one and |
| 518 |
// leave it unlocked - thereby allowing in-place changes - until someone asks for a pointer to |
| 519 |
// the table. Then, we will lock it. Then both our future changes and their future changes |
| 520 |
// will first have to make a copy. This discipline means that usually when we create a |
| 521 |
// ScopedArguments object, we don't have to make a copy of the ScopedArgumentsTable - instead |
| 522 |
// we just take a reference to one that we already have. |
| 523 |
|
| 524 |
uint32_t argumentsLength() const |
| 525 |
{ |
| 526 |
if (!m_arguments) |
| 527 |
return 0; |
| 528 |
return m_arguments->length(); |
| 529 |
} |
| 530 |
|
| 531 |
void setArgumentsLength(VM& vm, uint32_t length) |
| 532 |
{ |
| 533 |
if (UNLIKELY(!m_arguments)) |
| 534 |
m_arguments.set(vm, this, ScopedArgumentsTable::create(vm)); |
| 535 |
m_arguments.set(vm, this, m_arguments->setLength(vm, length)); |
| 536 |
} |
| 537 |
|
| 538 |
ScopeOffset argumentOffset(uint32_t i) const |
| 539 |
{ |
| 540 |
ASSERT_WITH_SECURITY_IMPLICATION(m_arguments); |
| 541 |
return m_arguments->get(i); |
| 542 |
} |
| 543 |
|
| 544 |
void setArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset) |
| 545 |
{ |
| 546 |
ASSERT_WITH_SECURITY_IMPLICATION(m_arguments); |
| 547 |
m_arguments.set(vm, this, m_arguments->set(vm, i, offset)); |
| 548 |
} |
| 549 |
|
| 550 |
ScopedArgumentsTable* arguments() const |
| 551 |
{ |
| 552 |
m_arguments->lock(); |
| 553 |
return m_arguments.get(); |
| 554 |
} |
| 555 |
|
| 459 |
GlobalVariableID uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm); |
556 |
GlobalVariableID uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm); |
| 460 |
GlobalVariableID uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm); |
557 |
GlobalVariableID uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm); |
| 461 |
RefPtr<TypeSet> globalTypeSetForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm); |
558 |
RefPtr<TypeSet> globalTypeSetForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm); |
|
Lines 464-491
public:
Source/JavaScriptCore/runtime/SymbolTable.h_sec14
|
| 464 |
bool usesNonStrictEval() { return m_usesNonStrictEval; } |
561 |
bool usesNonStrictEval() { return m_usesNonStrictEval; } |
| 465 |
void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } |
562 |
void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } |
| 466 |
|
563 |
|
| 467 |
int captureStart() const { return m_captureStart; } |
564 |
SymbolTable* cloneScopePart(VM&); |
| 468 |
void setCaptureStart(int captureStart) { m_captureStart = captureStart; } |
|
|
| 469 |
|
| 470 |
int captureEnd() const { return m_captureEnd; } |
| 471 |
void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; } |
| 472 |
|
| 473 |
int captureCount() const { return -(m_captureEnd - m_captureStart); } |
| 474 |
|
| 475 |
bool isCaptured(int operand) |
| 476 |
{ |
| 477 |
return operand <= captureStart() && operand > captureEnd(); |
| 478 |
} |
| 479 |
|
| 480 |
int parameterCount() { return m_parameterCountIncludingThis - 1; } |
| 481 |
int parameterCountIncludingThis() { return m_parameterCountIncludingThis; } |
| 482 |
void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; } |
| 483 |
|
| 484 |
// 0 if we don't capture any arguments; parameterCount() in length if we do. |
| 485 |
const SlowArgument* slowArguments() { return m_slowArguments.get(); } |
| 486 |
void setSlowArguments(std::unique_ptr<SlowArgument[]> slowArguments) { m_slowArguments = WTF::move(slowArguments); } |
| 487 |
|
| 488 |
SymbolTable* cloneCapturedNames(VM&); |
| 489 |
|
565 |
|
| 490 |
void prepareForTypeProfiling(const ConcurrentJITLocker&); |
566 |
void prepareForTypeProfiling(const ConcurrentJITLocker&); |
| 491 |
|
567 |
|
|
Lines 513-518
private:
Source/JavaScriptCore/runtime/SymbolTable.h_sec15
|
| 513 |
~SymbolTable(); |
589 |
~SymbolTable(); |
| 514 |
|
590 |
|
| 515 |
Map m_map; |
591 |
Map m_map; |
|
|
592 |
ScopeOffset m_maxScopeOffset; |
| 593 |
|
| 516 |
struct TypeProfilingRareData { |
594 |
struct TypeProfilingRareData { |
| 517 |
UniqueIDMap m_uniqueIDMap; |
595 |
UniqueIDMap m_uniqueIDMap; |
| 518 |
RegisterToVariableMap m_registerToVariableMap; |
596 |
RegisterToVariableMap m_registerToVariableMap; |
|
Lines 520-532
private:
Source/JavaScriptCore/runtime/SymbolTable.h_sec16
|
| 520 |
}; |
598 |
}; |
| 521 |
std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData; |
599 |
std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData; |
| 522 |
|
600 |
|
| 523 |
int m_parameterCountIncludingThis; |
|
|
| 524 |
bool m_usesNonStrictEval; |
601 |
bool m_usesNonStrictEval; |
| 525 |
|
602 |
|
| 526 |
int m_captureStart; |
603 |
WriteBarrier<ScopedArgumentsTable> m_arguments; |
| 527 |
int m_captureEnd; |
|
|
| 528 |
|
| 529 |
std::unique_ptr<SlowArgument[]> m_slowArguments; |
| 530 |
|
604 |
|
| 531 |
std::unique_ptr<WatchpointCleanup> m_watchpointCleanup; |
605 |
std::unique_ptr<WatchpointCleanup> m_watchpointCleanup; |
| 532 |
|
606 |
|