summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/interpreter')
-rw-r--r--JavaScriptCore/interpreter/CallFrame.h1
-rw-r--r--JavaScriptCore/interpreter/Interpreter.cpp419
-rw-r--r--JavaScriptCore/interpreter/Interpreter.h235
-rw-r--r--JavaScriptCore/interpreter/Register.h3
-rw-r--r--JavaScriptCore/interpreter/RegisterFile.h139
5 files changed, 111 insertions, 686 deletions
diff --git a/JavaScriptCore/interpreter/CallFrame.h b/JavaScriptCore/interpreter/CallFrame.h
index d6b9b79..10d0b99 100644
--- a/JavaScriptCore/interpreter/CallFrame.h
+++ b/JavaScriptCore/interpreter/CallFrame.h
@@ -97,6 +97,7 @@ namespace JSC {
friend class JSActivation;
friend class JSGlobalObject;
friend class Interpreter;
+ friend class JITStubs;
static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
Register* registers() { return this; }
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 135c42f..8178d15 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -66,29 +66,10 @@
#include "AssemblerBuffer.h"
#endif
-#if PLATFORM(DARWIN)
-#include <mach/mach.h>
-#endif
-
-#if HAVE(SYS_TIME_H)
-#include <sys/time.h>
-#endif
-
-#if PLATFORM(WIN_OS)
-#include <windows.h>
-#endif
-
-#if PLATFORM(QT)
-#include <QDateTime>
-#endif
-
using namespace std;
namespace JSC {
-// Preferred number of milliseconds between each timeout check
-static const int preferredScriptCheckTimeInterval = 1000;
-
static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
{
#if ENABLE(JIT)
@@ -107,162 +88,6 @@ static int depth(CodeBlock* codeBlock, ScopeChain& sc)
return sc.localDepth();
}
-static inline bool jsLess(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
-{
- if (JSValuePtr::areBothInt32Fast(v1, v2))
- return v1.getInt32Fast() < v2.getInt32Fast();
-
- double n1;
- double n2;
- if (v1.getNumber(n1) && v2.getNumber(n2))
- return n1 < n2;
-
- Interpreter* interpreter = callFrame->interpreter();
- if (interpreter->isJSString(v1) && interpreter->isJSString(v2))
- return asString(v1)->value() < asString(v2)->value();
-
- JSValuePtr p1;
- JSValuePtr p2;
- bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
- bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
-
- if (wasNotString1 | wasNotString2)
- return n1 < n2;
-
- return asString(p1)->value() < asString(p2)->value();
-}
-
-static inline bool jsLessEq(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
-{
- if (JSValuePtr::areBothInt32Fast(v1, v2))
- return v1.getInt32Fast() <= v2.getInt32Fast();
-
- double n1;
- double n2;
- if (v1.getNumber(n1) && v2.getNumber(n2))
- return n1 <= n2;
-
- Interpreter* interpreter = callFrame->interpreter();
- if (interpreter->isJSString(v1) && interpreter->isJSString(v2))
- return !(asString(v2)->value() < asString(v1)->value());
-
- JSValuePtr p1;
- JSValuePtr p2;
- bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
- bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
-
- if (wasNotString1 | wasNotString2)
- return n1 <= n2;
-
- return !(asString(p2)->value() < asString(p1)->value());
-}
-
-static NEVER_INLINE JSValuePtr jsAddSlowCase(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
-{
- // exception for the Date exception in defaultValue()
- JSValuePtr p1 = v1.toPrimitive(callFrame);
- JSValuePtr p2 = v2.toPrimitive(callFrame);
-
- if (p1.isString() || p2.isString()) {
- RefPtr<UString::Rep> value = concatenate(p1.toString(callFrame).rep(), p2.toString(callFrame).rep());
- if (!value)
- return throwOutOfMemoryError(callFrame);
- return jsString(callFrame, value.release());
- }
-
- return jsNumber(callFrame, p1.toNumber(callFrame) + p2.toNumber(callFrame));
-}
-
-// Fast-path choices here are based on frequency data from SunSpider:
-// <times> Add case: <t1> <t2>
-// ---------------------------
-// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
-// 247412 Add case: 5 5
-// 20900 Add case: 5 6
-// 13962 Add case: 5 3
-// 4000 Add case: 3 5
-
-static ALWAYS_INLINE JSValuePtr jsAdd(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
-{
- double left;
- double right = 0.0;
-
- bool rightIsNumber = v2.getNumber(right);
- if (rightIsNumber && v1.getNumber(left))
- return jsNumber(callFrame, left + right);
-
- bool leftIsString = v1.isString();
- if (leftIsString && v2.isString()) {
- RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
- if (!value)
- return throwOutOfMemoryError(callFrame);
- return jsString(callFrame, value.release());
- }
-
- if (rightIsNumber & leftIsString) {
- RefPtr<UString::Rep> value = v2.isInt32Fast() ?
- concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) :
- concatenate(asString(v1)->value().rep(), right);
-
- if (!value)
- return throwOutOfMemoryError(callFrame);
- return jsString(callFrame, value.release());
- }
-
- // All other cases are pretty uncommon
- return jsAddSlowCase(callFrame, v1, v2);
-}
-
-static JSValuePtr jsTypeStringForValue(CallFrame* callFrame, JSValuePtr v)
-{
- if (v.isUndefined())
- return jsNontrivialString(callFrame, "undefined");
- if (v.isBoolean())
- return jsNontrivialString(callFrame, "boolean");
- if (v.isNumber())
- return jsNontrivialString(callFrame, "number");
- if (v.isString())
- return jsNontrivialString(callFrame, "string");
- if (v.isObject()) {
- // Return "undefined" for objects that should be treated
- // as null when doing comparisons.
- if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
- return jsNontrivialString(callFrame, "undefined");
- CallData callData;
- if (asObject(v)->getCallData(callData) != CallTypeNone)
- return jsNontrivialString(callFrame, "function");
- }
- return jsNontrivialString(callFrame, "object");
-}
-
-static bool jsIsObjectType(JSValuePtr v)
-{
- if (!v.isCell())
- return v.isNull();
-
- JSType type = asCell(v)->structure()->typeInfo().type();
- if (type == NumberType || type == StringType)
- return false;
- if (type == ObjectType) {
- if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
- return false;
- CallData callData;
- if (asObject(v)->getCallData(callData) != CallTypeNone)
- return false;
- }
- return true;
-}
-
-static bool jsIsFunctionType(JSValuePtr v)
-{
- if (v.isObject()) {
- CallData callData;
- if (asObject(v)->getCallData(callData) != CallTypeNone)
- return true;
- }
- return false;
-}
-
NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
{
int dst = (vPC + 1)->u.operand;
@@ -364,34 +189,11 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction*
return false;
}
-static ALWAYS_INLINE JSValuePtr inlineResolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
-{
- ScopeChainIterator iter = scopeChain->begin();
- ScopeChainIterator next = iter;
- ++next;
- ScopeChainIterator end = scopeChain->end();
- ASSERT(iter != end);
-
- PropertySlot slot;
- JSObject* base;
- while (true) {
- base = *iter;
- if (next == end || base->getPropertySlot(callFrame, property, slot))
- return base;
-
- iter = next;
- ++next;
- }
-
- ASSERT_NOT_REACHED();
- return noValue();
-}
-
NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
{
int dst = (vPC + 1)->u.operand;
int property = (vPC + 2)->u.operand;
- callFrame[dst] = JSValuePtr(inlineResolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
+ callFrame[dst] = JSValuePtr(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
}
NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
@@ -545,56 +347,9 @@ NEVER_INLINE JSValuePtr Interpreter::callEval(CallFrame* callFrame, RegisterFile
Interpreter::Interpreter()
: m_sampler(0)
-#if ENABLE(JIT)
- , m_ctiArrayLengthTrampoline(0)
- , m_ctiStringLengthTrampoline(0)
- , m_ctiVirtualCallPreLink(0)
- , m_ctiVirtualCallLink(0)
- , m_ctiVirtualCall(0)
-#endif
, m_reentryDepth(0)
- , m_timeoutTime(0)
- , m_timeAtLastCheckTimeout(0)
- , m_timeExecuting(0)
- , m_timeoutCheckCount(0)
- , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
{
- initTimeout();
privateExecute(InitializeAndReturn, 0, 0, 0);
-
- // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
- void* storage = fastMalloc(sizeof(CollectorBlock));
-
- JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
- m_jsArrayVptr = jsArray->vptr();
- jsArray->~JSCell();
-
- JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
- m_jsByteArrayVptr = jsByteArray->vptr();
- jsByteArray->~JSCell();
-
- JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
- m_jsStringVptr = jsString->vptr();
- jsString->~JSCell();
-
- JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
- m_jsFunctionVptr = jsFunction->vptr();
- jsFunction->~JSCell();
-
- fastFree(storage);
-}
-
-void Interpreter::initialize(JSGlobalData* globalData)
-{
-#if ENABLE(JIT)
- JIT::compileCTIMachineTrampolines(globalData);
-#else
- UNUSED_PARAM(globalData);
-#endif
-}
-
-Interpreter::~Interpreter()
-{
}
#ifndef NDEBUG
@@ -865,7 +620,7 @@ JSValuePtr Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame,
#if ENABLE(JIT)
if (!codeBlock->jitCode())
JIT::compile(scopeChain->globalData, codeBlock);
- result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+ result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
#else
result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
#endif
@@ -931,7 +686,7 @@ JSValuePtr Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* c
#if ENABLE(JIT)
if (!codeBlock->jitCode())
JIT::compile(scopeChain->globalData, codeBlock);
- result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+ result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
#else
result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
#endif
@@ -1023,7 +778,7 @@ JSValuePtr Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObje
#if ENABLE(JIT)
if (!codeBlock->jitCode())
JIT::compile(scopeChain->globalData, codeBlock);
- result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+ result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
#else
result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
#endif
@@ -1065,93 +820,6 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook
}
}
-void Interpreter::resetTimeoutCheck()
-{
- m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
- m_timeAtLastCheckTimeout = 0;
- m_timeExecuting = 0;
-}
-
-// Returns the time the current thread has spent executing, in milliseconds.
-static inline unsigned getCPUTime()
-{
-#if PLATFORM(DARWIN)
- mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
- thread_basic_info_data_t info;
-
- // Get thread information
- mach_port_t threadPort = mach_thread_self();
- thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
- mach_port_deallocate(mach_task_self(), threadPort);
-
- unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
- time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
-
- return time;
-#elif HAVE(SYS_TIME_H)
- // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
- struct timeval tv;
- gettimeofday(&tv, 0);
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-#elif PLATFORM(QT)
- QDateTime t = QDateTime::currentDateTime();
- return t.toTime_t() * 1000 + t.time().msec();
-#elif PLATFORM(WIN_OS)
- union {
- FILETIME fileTime;
- unsigned long long fileTimeAsLong;
- } userTime, kernelTime;
-
- // GetThreadTimes won't accept NULL arguments so we pass these even though
- // they're not used.
- FILETIME creationTime, exitTime;
-
- GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
-
- return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
-#else
-#error Platform does not have getCurrentTime function
-#endif
-}
-
-// We have to return a JSValue here, gcc seems to produce worse code if
-// we attempt to return a bool
-ALWAYS_INLINE bool Interpreter::checkTimeout(JSGlobalObject* globalObject)
-{
- unsigned currentTime = getCPUTime();
-
- if (!m_timeAtLastCheckTimeout) {
- // Suspicious amount of looping in a script -- start timing it
- m_timeAtLastCheckTimeout = currentTime;
- return false;
- }
-
- unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
-
- if (timeDiff == 0)
- timeDiff = 1;
-
- m_timeExecuting += timeDiff;
- m_timeAtLastCheckTimeout = currentTime;
-
- // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
- // preferredScriptCheckTimeInterval
- m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
- // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
- // preferred script check time interval.
- if (m_ticksUntilNextTimeoutCheck == 0)
- m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
-
- if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
- if (globalObject->shouldInterruptScript())
- return true;
-
- resetTimeoutCheck();
- }
-
- return false;
-}
-
NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
{
int dst = (++vPC)->u.operand;
@@ -1251,37 +919,6 @@ NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction*
vPC[4] = 0;
}
-static size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValuePtr baseValue, const PropertySlot& slot)
-{
- JSCell* cell = asCell(baseValue);
- size_t count = 0;
-
- while (slot.slotBase() != cell) {
- JSValuePtr v = cell->structure()->prototypeForLookup(callFrame);
-
- // If we didn't find slotBase in baseValue's prototype chain, then baseValue
- // must be a proxy for another object.
-
- if (v.isNull())
- return 0;
-
- cell = asCell(v);
-
- // Since we're accessing a prototype in a loop, it's a good bet that it
- // should not be treated as a dictionary.
- if (cell->structure()->isDictionary()) {
- RefPtr<Structure> transition = Structure::fromDictionaryTransition(cell->structure());
- asObject(cell)->setStructure(transition.release());
- cell->structure()->setCachedPrototypeChain(0);
- }
-
- ++count;
- }
-
- ASSERT(count);
- return count;
-}
-
NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot& slot)
{
// Recursive invocation may already have specialized this instruction.
@@ -1294,12 +931,13 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
return;
}
- if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
+ JSGlobalData* globalData = &callFrame->globalData();
+ if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
vPC[0] = getOpcode(op_get_array_length);
return;
}
- if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {
+ if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
vPC[0] = getOpcode(op_get_string_length);
return;
}
@@ -1417,7 +1055,7 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
Instruction* vPC = callFrame->codeBlock()->instructions().begin();
Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
- unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
+ unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
#define CHECK_FOR_EXCEPTION() \
do { \
@@ -1433,19 +1071,17 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
#define CHECK_FOR_TIMEOUT() \
if (!--tickCount) { \
- if (checkTimeout(callFrame->dynamicGlobalObject())) { \
+ if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
exceptionValue = jsNull(); \
goto vm_throw; \
} \
- tickCount = m_ticksUntilNextTimeoutCheck; \
+ tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
}
#if ENABLE(OPCODE_SAMPLING)
#define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
- #define CTI_SAMPLER ARG_globalData->interpreter->sampler()
#else
#define SAMPLE(codeBlock, vPC)
- #define CTI_SAMPLER 0
#endif
#if HAVE(COMPUTED_GOTO)
@@ -2123,7 +1759,12 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
goto vm_throw;
JSObject* baseObj = asObject(baseVal);
- callFrame[dst] = jsBoolean(baseObj->structure()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame)) : false);
+ if (baseObj->structure()->typeInfo().implementsHasInstance()) {
+ bool result = baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame));
+ CHECK_FOR_EXCEPTION();
+ callFrame[dst] = jsBoolean(result);
+ } else
+ callFrame[dst] = jsBoolean(false);
vPC += 5;
NEXT_INSTRUCTION();
@@ -2607,7 +2248,7 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
int base = vPC[2].u.operand;
JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
- if (LIKELY(isJSArray(baseValue))) {
+ if (LIKELY(isJSArray(globalData, baseValue))) {
int dst = vPC[1].u.operand;
callFrame[dst] = JSValuePtr(jsNumber(callFrame, asArray(baseValue)->length()));
vPC += 8;
@@ -2627,7 +2268,7 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
int base = vPC[2].u.operand;
JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
- if (LIKELY(isJSString(baseValue))) {
+ if (LIKELY(isJSString(globalData, baseValue))) {
int dst = vPC[1].u.operand;
callFrame[dst] = JSValuePtr(jsNumber(callFrame, asString(baseValue)->value().size()));
vPC += 8;
@@ -2809,15 +2450,15 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
if (LIKELY(subscript.isUInt32Fast())) {
uint32_t i = subscript.getUInt32Fast();
- if (isJSArray(baseValue)) {
+ if (isJSArray(globalData, baseValue)) {
JSArray* jsArray = asArray(baseValue);
if (jsArray->canGetIndex(i))
result = jsArray->getIndex(i);
else
result = jsArray->JSArray::get(callFrame, i);
- } else if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
+ } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
result = asString(baseValue)->getIndex(&callFrame->globalData(), i);
- else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i))
+ else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
result = asByteArray(baseValue)->getIndex(callFrame, i);
else
result = baseValue.get(callFrame, i);
@@ -2851,13 +2492,13 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
if (LIKELY(subscript.isUInt32Fast())) {
uint32_t i = subscript.getUInt32Fast();
- if (isJSArray(baseValue)) {
+ if (isJSArray(globalData, baseValue)) {
JSArray* jsArray = asArray(baseValue);
if (jsArray->canSetIndex(i))
jsArray->setIndex(i, callFrame[value].jsValue(callFrame));
else
jsArray->JSArray::put(callFrame, i, callFrame[value].jsValue(callFrame));
- } else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
+ } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
JSByteArray* jsByteArray = asByteArray(baseValue);
double dValue = 0;
JSValuePtr jsValue = callFrame[value].jsValue(callFrame);
@@ -3144,9 +2785,10 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
if (scrutinee.isInt32Fast())
vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.getInt32Fast(), defaultOffset);
else {
- int32_t value;
- if (scrutinee.numberToInt32(value))
- vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(value, defaultOffset);
+ double value;
+ int32_t intValue;
+ if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
+ vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
else
vPC += defaultOffset;
}
@@ -3591,7 +3233,7 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
the object in register override to register dst.
*/
- int dst = vPC[1].u.operand;;
+ int dst = vPC[1].u.operand;
if (LIKELY(callFrame[dst].jsValue(callFrame).isObject())) {
vPC += 3;
NEXT_INSTRUCTION();
@@ -3711,7 +3353,7 @@ JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registe
DEFINE_OPCODE(op_catch) {
/* catch ex(r)
- Retrieves the VMs current exception and puts it in register
+ Retrieves the VM's current exception and puts it in register
ex. This is only valid after an exception has been raised,
and usually forms the beginning of an exception handler.
*/
@@ -4004,6 +3646,7 @@ CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunc
return 0;
}
+#ifdef MANUAL_MERGE_REQUIRED
#if ENABLE(JIT)
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
@@ -6137,4 +5780,6 @@ JSValueEncodedAsPointer* Interpreter::cti_vm_throw(STUB_ARGS)
#endif // ENABLE(JIT)
+#else // MANUAL_MERGE_REQUIRED
+#endif // MANUAL_MERGE_REQUIRED
} // namespace JSC
diff --git a/JavaScriptCore/interpreter/Interpreter.h b/JavaScriptCore/interpreter/Interpreter.h
index 18c2185..7d97962 100644
--- a/JavaScriptCore/interpreter/Interpreter.h
+++ b/JavaScriptCore/interpreter/Interpreter.h
@@ -32,6 +32,7 @@
#include "ArgList.h"
#include "JSCell.h"
#include "JSValue.h"
+#include "JSObject.h"
#include "Opcode.h"
#include "RegisterFile.h"
#include <wtf/HashMap.h>
@@ -56,52 +57,6 @@ namespace JSC {
class SamplingTool;
struct HandlerInfo;
-#if ENABLE(JIT)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
- #define STUB_ARGS void* args, ...
- #define ARGS (reinterpret_cast<void**>(vl_args) - 1)
-#else // JIT_STUB_ARGUMENT_REGISTER or JIT_STUB_ARGUMENT_STACK
- #define STUB_ARGS void** args
- #define ARGS (args)
-#endif
-
-#if USE(JIT_STUB_ARGUMENT_REGISTER)
- #if PLATFORM(X86_64)
- #define JIT_STUB
- #elif COMPILER(MSVC)
- #define JIT_STUB __fastcall
- #elif COMPILER(GCC)
- #define JIT_STUB __attribute__ ((fastcall))
- #else
- #error Need to support register calling convention in this compiler
- #endif
-#else // JIT_STUB_ARGUMENT_VA_LIST or JIT_STUB_ARGUMENT_STACK
- #if COMPILER(MSVC)
- #define JIT_STUB __cdecl
- #else
- #define JIT_STUB
- #endif
-#endif
-
-// The Mac compilers are fine with this,
-#if PLATFORM(MAC)
- struct VoidPtrPair {
- void* first;
- void* second;
- };
-#define RETURN_PAIR(a,b) VoidPtrPair pair = { a, b }; return pair
-#else
- typedef uint64_t VoidPtrPair;
- union VoidPtrPairValue {
- struct { void* first; void* second; } s;
- VoidPtrPair i;
- };
-#define RETURN_PAIR(a,b) VoidPtrPairValue pair = {{ a, b }}; return pair.i
-#endif
-
-#endif // ENABLE(JIT)
-
enum DebugHookID {
WillExecuteProgram,
DidExecuteProgram,
@@ -111,16 +66,15 @@ namespace JSC {
WillExecuteStatement
};
- enum { MaxReentryDepth = 128 };
+ enum { MaxReentryDepth = 64 };
class Interpreter {
friend class JIT;
+ friend class JITStubs;
+
public:
Interpreter();
- ~Interpreter();
- void initialize(JSGlobalData*);
-
RegisterFile& registerFile() { return m_registerFile; }
Opcode getOpcode(OpcodeID id)
@@ -153,161 +107,9 @@ namespace JSC {
void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValuePtr& function) const;
void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
- void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
-
- void startTimeoutCheck()
- {
- if (!m_timeoutCheckCount)
- resetTimeoutCheck();
-#ifdef ANDROID_INSTRUMENT
- if (!m_timeoutCheckCount)
- android::TimeCounter::start(android::TimeCounter::JavaScriptTimeCounter);
-#endif
-
- ++m_timeoutCheckCount;
- }
-
- void stopTimeoutCheck()
- {
- ASSERT(m_timeoutCheckCount);
- --m_timeoutCheckCount;
-#ifdef ANDROID_INSTRUMENT
- if (!m_timeoutCheckCount)
- android::TimeCounter::record(android::TimeCounter::JavaScriptTimeCounter, __FUNCTION__);
-#endif
- }
-
- inline void initTimeout()
- {
- ASSERT(!m_timeoutCheckCount);
- resetTimeoutCheck();
- m_timeoutTime = 0;
- m_timeoutCheckCount = 0;
- }
-
void setSampler(SamplingTool* sampler) { m_sampler = sampler; }
SamplingTool* sampler() { return m_sampler; }
-#if ENABLE(JIT)
-
- static int JIT_STUB cti_timeout_check(STUB_ARGS);
- static void JIT_STUB cti_register_file_check(STUB_ARGS);
-
- static JSObject* JIT_STUB cti_op_convert_this(STUB_ARGS);
- static void JIT_STUB cti_op_end(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_add(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_pre_inc(STUB_ARGS);
- static int JIT_STUB cti_op_loop_if_less(STUB_ARGS);
- static int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_object(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_id(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_id_second(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_id_generic(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_id_fail(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_second(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_generic(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_self_fail(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_proto_list_full(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_array_fail(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_id_string_fail(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_del_by_id(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_instanceof(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_mul(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_func(STUB_ARGS);
- static void* JIT_STUB cti_op_call_JSFunction(STUB_ARGS);
- static VoidPtrPair JIT_STUB cti_op_call_arityCheck(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS);
- static void JIT_STUB cti_op_create_arguments(STUB_ARGS);
- static void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS);
- static void JIT_STUB cti_op_tear_off_activation(STUB_ARGS);
- static void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS);
- static void JIT_STUB cti_op_profile_will_call(STUB_ARGS);
- static void JIT_STUB cti_op_profile_did_call(STUB_ARGS);
- static void JIT_STUB cti_op_ret_scopeChain(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_array(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_resolve(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_resolve_global(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_val(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_get_by_val_byte_array(STUB_ARGS);
- static VoidPtrPair JIT_STUB cti_op_resolve_func(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_sub(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_val(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_val_array(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_lesseq(STUB_ARGS);
- static int JIT_STUB cti_op_loop_if_true(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_resolve_base(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_negate(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_resolve_skip(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_div(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_pre_dec(STUB_ARGS);
- static int JIT_STUB cti_op_jless(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_not(STUB_ARGS);
- static int JIT_STUB cti_op_jtrue(STUB_ARGS);
- static VoidPtrPair JIT_STUB cti_op_post_inc(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_eq(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_lshift(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_bitand(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_rshift(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_bitnot(STUB_ARGS);
- static VoidPtrPair JIT_STUB cti_op_resolve_with_base(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_mod(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_less(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_neq(STUB_ARGS);
- static VoidPtrPair JIT_STUB cti_op_post_dec(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_urshift(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_bitxor(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_regexp(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_bitor(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_call_eval(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_throw(STUB_ARGS);
- static JSPropertyNameIterator* JIT_STUB cti_op_get_pnames(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_next_pname(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_push_scope(STUB_ARGS);
- static void JIT_STUB cti_op_pop_scope(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_typeof(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_undefined(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_boolean(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_number(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_string(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_object(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_is_function(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_stricteq(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_nstricteq(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_to_jsnumber(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_in(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_push_new_scope(STUB_ARGS);
- static void JIT_STUB cti_op_jmp_scopes(STUB_ARGS);
- static void JIT_STUB cti_op_put_by_index(STUB_ARGS);
- static void* JIT_STUB cti_op_switch_imm(STUB_ARGS);
- static void* JIT_STUB cti_op_switch_char(STUB_ARGS);
- static void* JIT_STUB cti_op_switch_string(STUB_ARGS);
- static JSValueEncodedAsPointer* JIT_STUB cti_op_del_by_val(STUB_ARGS);
- static void JIT_STUB cti_op_put_getter(STUB_ARGS);
- static void JIT_STUB cti_op_put_setter(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_new_error(STUB_ARGS);
- static void JIT_STUB cti_op_debug(STUB_ARGS);
-
- static JSValueEncodedAsPointer* JIT_STUB cti_vm_throw(STUB_ARGS);
- static void* JIT_STUB cti_vm_dontLazyLinkCall(STUB_ARGS);
- static void* JIT_STUB cti_vm_lazyLinkCall(STUB_ARGS);
- static JSObject* JIT_STUB cti_op_push_activation(STUB_ARGS);
-
-#endif // ENABLE(JIT)
-
- // Default number of ticks before a timeout check should be done.
- static const int initialTickCountThreshold = 1024;
-
- bool isJSArray(JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == m_jsArrayVptr; }
- bool isJSString(JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == m_jsStringVptr; }
- bool isJSByteArray(JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == m_jsByteArrayVptr; }
-
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
@@ -336,9 +138,6 @@ namespace JSC {
void dumpCallFrame(CallFrame*);
void dumpRegisters(CallFrame*);
- bool checkTimeout(JSGlobalObject*);
- void resetTimeoutCheck();
-
void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot&);
void uncacheGetByID(CodeBlock*, Instruction* vPC);
void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValuePtr baseValue, const PutPropertySlot&);
@@ -346,38 +145,12 @@ namespace JSC {
bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
-#if ENABLE(JIT)
- static void throwStackOverflowPreviousFrame(CallFrame**, JSGlobalData*, void*& returnAddress);
-
- void tryCTICacheGetByID(CallFrame*, CodeBlock*, void* returnAddress, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot&);
- void tryCTICachePutByID(CallFrame*, CodeBlock*, void* returnAddress, JSValuePtr baseValue, const PutPropertySlot&);
-#endif
-
SamplingTool* m_sampler;
-#if ENABLE(JIT)
- RefPtr<ExecutablePool> m_executablePool;
- void* m_ctiArrayLengthTrampoline;
- void* m_ctiStringLengthTrampoline;
- void* m_ctiVirtualCallPreLink;
- void* m_ctiVirtualCallLink;
- void* m_ctiVirtualCall;
-#endif
-
int m_reentryDepth;
- unsigned m_timeoutTime;
- unsigned m_timeAtLastCheckTimeout;
- unsigned m_timeExecuting;
- unsigned m_timeoutCheckCount;
- unsigned m_ticksUntilNextTimeoutCheck;
RegisterFile m_registerFile;
- void* m_jsArrayVptr;
- void* m_jsByteArrayVptr;
- void* m_jsStringVptr;
- void* m_jsFunctionVptr;
-
#if HAVE(COMPUTED_GOTO)
Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
diff --git a/JavaScriptCore/interpreter/Register.h b/JavaScriptCore/interpreter/Register.h
index ff36bbc..5277a0f 100644
--- a/JavaScriptCore/interpreter/Register.h
+++ b/JavaScriptCore/interpreter/Register.h
@@ -60,8 +60,9 @@ namespace JSC {
private:
friend class ExecState;
friend class Interpreter;
+ friend class JITStubs;
- // Only CallFrame and Interpreter should use these functions.
+ // Only CallFrame, Interpreter, and JITStubs should use these functions.
Register(intptr_t);
diff --git a/JavaScriptCore/interpreter/RegisterFile.h b/JavaScriptCore/interpreter/RegisterFile.h
index ec190d6..c320f04 100644
--- a/JavaScriptCore/interpreter/RegisterFile.h
+++ b/JavaScriptCore/interpreter/RegisterFile.h
@@ -29,6 +29,7 @@
#ifndef RegisterFile_h
#define RegisterFile_h
+#include "ExecutableAllocator.h"
#include "Register.h"
#include "Collector.h"
#include <wtf/Noncopyable.h>
@@ -111,48 +112,9 @@ namespace JSC {
static const size_t defaultCapacity = 524288;
static const size_t defaultMaxGlobals = 8192;
- static const size_t allocationSize = 1 << 14;
- static const size_t allocationSizeMask = allocationSize - 1;
-
- RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals)
- : m_numGlobals(0)
- , m_maxGlobals(maxGlobals)
- , m_start(0)
- , m_end(0)
- , m_max(0)
- , m_buffer(0)
- , m_globalObject(0)
- {
- size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
-#if HAVE(MMAP)
- m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0));
- if (m_buffer == MAP_FAILED) {
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
- CRASH();
- }
-#elif HAVE(VIRTUALALLOC)
- // Ensure bufferLength is a multiple of allocation size
- bufferLength = (bufferLength + allocationSizeMask) & ~allocationSizeMask;
- m_buffer = static_cast<Register*>(VirtualAlloc(0, bufferLength, MEM_RESERVE, PAGE_READWRITE));
- if (!m_buffer) {
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
- CRASH();
- }
- int initialAllocation = (maxGlobals * sizeof(Register) + allocationSizeMask) & ~allocationSizeMask;
- void* commitCheck = VirtualAlloc(m_buffer, initialAllocation, MEM_COMMIT, PAGE_READWRITE);
- if (commitCheck != m_buffer) {
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
- CRASH();
- }
- m_maxCommitted = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + initialAllocation);
-#else
- #error "Don't know how to reserve virtual memory on this platform."
-#endif
- m_start = m_buffer + maxGlobals;
- m_end = m_start;
- m_max = m_start + capacity;
- }
+ static const size_t commitSize = 1 << 14;
+ RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
~RegisterFile();
Register* start() const { return m_start; }
@@ -162,31 +124,8 @@ namespace JSC {
void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; }
JSGlobalObject* globalObject() { return m_globalObject; }
- void shrink(Register* newEnd)
- {
- if (newEnd < m_end)
- m_end = newEnd;
- }
-
- bool grow(Register* newEnd)
- {
- if (newEnd > m_end) {
- if (newEnd > m_max)
- return false;
-#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
- if (newEnd > m_maxCommitted) {
- ptrdiff_t additionalAllocation = ((reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_maxCommitted)) + allocationSizeMask) & ~allocationSizeMask;
- if (!VirtualAlloc(m_maxCommitted, additionalAllocation, MEM_COMMIT, PAGE_READWRITE)) {
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
- CRASH();
- }
- m_maxCommitted = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_maxCommitted) + additionalAllocation);
- }
-#endif
- m_end = newEnd;
- }
- return true;
- }
+ bool grow(Register* newEnd);
+ void shrink(Register* newEnd);
void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
int numGlobals() const { return m_numGlobals; }
@@ -205,12 +144,78 @@ namespace JSC {
Register* m_max;
Register* m_buffer;
#if HAVE(VIRTUALALLOC)
- Register* m_maxCommitted;
+ Register* m_commitEnd;
#endif
JSGlobalObject* m_globalObject; // The global object whose vars are currently stored in the register file.
};
+ inline RegisterFile::RegisterFile(size_t capacity, size_t maxGlobals)
+ : m_numGlobals(0)
+ , m_maxGlobals(maxGlobals)
+ , m_start(0)
+ , m_end(0)
+ , m_max(0)
+ , m_buffer(0)
+ , m_globalObject(0)
+ {
+ size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
+ #if HAVE(MMAP)
+ m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0));
+ if (m_buffer == MAP_FAILED) {
+ fprintf(stderr, "Could not allocate register file: %d\n", errno);
+ CRASH();
+ }
+ #elif HAVE(VIRTUALALLOC)
+ m_buffer = static_cast<Register*>(VirtualAlloc(0, roundUpAllocationSize(bufferLength, commitSize), MEM_RESERVE, PAGE_READWRITE));
+ if (!m_buffer) {
+ fprintf(stderr, "Could not allocate register file: %d\n", errno);
+ CRASH();
+ }
+ size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize);
+ void* commitCheck = VirtualAlloc(m_buffer, committedSize, MEM_COMMIT, PAGE_READWRITE);
+ if (commitCheck != m_buffer) {
+ fprintf(stderr, "Could not allocate register file: %d\n", errno);
+ CRASH();
+ }
+ m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + committedSize);
+ #else
+ #error "Don't know how to reserve virtual memory on this platform."
+ #endif
+ m_start = m_buffer + maxGlobals;
+ m_end = m_start;
+ m_max = m_start + capacity;
+ }
+
+ inline void RegisterFile::shrink(Register* newEnd)
+ {
+ if (newEnd < m_end)
+ m_end = newEnd;
+ }
+
+ inline bool RegisterFile::grow(Register* newEnd)
+ {
+ if (newEnd < m_end)
+ return true;
+
+ if (newEnd > m_max)
+ return false;
+
+#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
+ if (newEnd > m_commitEnd) {
+ size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
+ if (!VirtualAlloc(m_commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) {
+ fprintf(stderr, "Could not allocate register file: %d\n", errno);
+ CRASH();
+ }
+ m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
+ }
+#endif
+
+ m_end = newEnd;
+ return true;
+ }
+
} // namespace JSC
#endif // RegisterFile_h