Commit 82a62d05 authored by ggaren@apple.com's avatar ggaren@apple.com

JavaScriptCore:

2008-06-27  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Oliver Hunt.
        
        One RegisterFile to rule them all!
        
        SunSpider reports a 0.2% speedup.

        This patch removes the RegisterFileStack abstraction and replaces it with
        a single register file that
        
        (a) allocates a fixed storage area, including a fixed area for global
        vars, so that no operation may cause the register file to reallocate
        
        and

        (b) swaps between global storage areas when executing code in different 
        global objects.
        
        This patch also changes the layout of the register file so that all call
        frames, including call frames for global code, get a header. This is
        required to support re-entrant global code. It also just makes things simpler.
        
        * VM/CodeGenerator.cpp:
        (KJS::CodeGenerator::addGlobalVar): New function. Differs from addVar in
        that
        
        (a) global vars don't contribute to a CodeBlock's numLocals count, since
        global storage is fixed and allocated at startup
        
        and
        
        (b) references to global vars get shifted to elide intermediate stack
        between "r" and the global storage area.
        
        * VM/Machine.cpp:
        (KJS::Machine::dumpRegisters): Updated this function to match the new
        register file layout, and added the ability to dump exact identifiers
        for the different parts of a call frame.
        
        (KJS::Machine::unwindCallFrame): Updated this function to match the new
        register file layout.
         
        (KJS::Machine::execute): Updated this function to initialize a call frame
        header for global code, and to swap global storage areas when switching
        to execution in a new global object.
        
        (KJS::Machine::privateExecute): Got rid of "safeForReentry" and re-reading
        of registerBase because the register file is always safe for reentry now,
        and registerBase never changes.
        
        * VM/Machine.h: Moved the call frame header enum from Machine to RegisterFile,
        to resolve a header dependency problem (a good sign that the enum belonged
        in RegisterFile all along!)

        * VM/RegisterFile.cpp:
        * VM/RegisterFile.h: Changed RegisterFile to mmap a fixed size register
        area. This allows us to avoid re-allocting the register file later on.
        Instead, we rely on the OS to allocate physical pages to the register
        file as necessary.

        * VM/RegisterFileStack.cpp: Removed. Tada!
        * VM/RegisterFileStack.h: Removed. Tada!

        * kjs/DebuggerCallFrame.cpp: Updated this class to match the new
        register file layout, greatly simplifying it in the process.

        * kjs/JSActivation.h:
        * kjs/JSActivation.cpp: Moved some of this logic up to JSVariableObject,
        since the global object now needs to be able to tear off its registers
        just like the activation object.

        * kjs/JSFunction.cpp: No need to fiddle with the register file anymore.

        * kjs/JSGlobalObject.h:
        * kjs/JSGlobalObject.cpp: Updated JSGlobalObject to support moving its
        global storage area into and out of the register file.

        * kjs/PropertySlot.cpp: No need to fiddle with the register file anymore.

        * kjs/collector.cpp: Renamed markStackObjectConservatively to
        markConservatively, since we don't just mark stack objects this way.
        
        Also, added code to mark the machine's register file.

        * kjs/config.h: Moved some platforms #defines from here...
        * wtf/Platform.h: ...to here, to support mmap/VirtualAlloc detection
        in RegisterFile.h.

LayoutTests:

2008-06-26  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Oliver Hunt.
        
        Added a test for what happens when a script exceeds the limit on declared
        global variables.

        * fast/js/global-var-limit-expected.txt: Added.
        * fast/js/global-var-limit.html: Added.

        * fast/js/global-recursion-on-full-stack-expected.txt: Updated for new
        (slightly more correct) behavior. Since the stack overflow happens in the
        middle of a try/catch block, it should be caught, instead of logged to
        the console.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34838 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0f431a15
2008-06-27 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
One RegisterFile to rule them all!
SunSpider reports a 0.2% speedup.
This patch removes the RegisterFileStack abstraction and replaces it with
a single register file that
(a) allocates a fixed storage area, including a fixed area for global
vars, so that no operation may cause the register file to reallocate
and
(b) swaps between global storage areas when executing code in different
global objects.
This patch also changes the layout of the register file so that all call
frames, including call frames for global code, get a header. This is
required to support re-entrant global code. It also just makes things simpler.
* VM/CodeGenerator.cpp:
(KJS::CodeGenerator::addGlobalVar): New function. Differs from addVar in
that
(a) global vars don't contribute to a CodeBlock's numLocals count, since
global storage is fixed and allocated at startup
and
(b) references to global vars get shifted to elide intermediate stack
between "r" and the global storage area.
* VM/Machine.cpp:
(KJS::Machine::dumpRegisters): Updated this function to match the new
register file layout, and added the ability to dump exact identifiers
for the different parts of a call frame.
(KJS::Machine::unwindCallFrame): Updated this function to match the new
register file layout.
(KJS::Machine::execute): Updated this function to initialize a call frame
header for global code, and to swap global storage areas when switching
to execution in a new global object.
(KJS::Machine::privateExecute): Got rid of "safeForReentry" and re-reading
of registerBase because the register file is always safe for reentry now,
and registerBase never changes.
* VM/Machine.h: Moved the call frame header enum from Machine to RegisterFile,
to resolve a header dependency problem (a good sign that the enum belonged
in RegisterFile all along!)
* VM/RegisterFile.cpp:
* VM/RegisterFile.h: Changed RegisterFile to mmap a fixed size register
area. This allows us to avoid re-allocting the register file later on.
Instead, we rely on the OS to allocate physical pages to the register
file as necessary.
* VM/RegisterFileStack.cpp: Removed. Tada!
* VM/RegisterFileStack.h: Removed. Tada!
* kjs/DebuggerCallFrame.cpp: Updated this class to match the new
register file layout, greatly simplifying it in the process.
* kjs/JSActivation.h:
* kjs/JSActivation.cpp: Moved some of this logic up to JSVariableObject,
since the global object now needs to be able to tear off its registers
just like the activation object.
* kjs/JSFunction.cpp: No need to fiddle with the register file anymore.
* kjs/JSGlobalObject.h:
* kjs/JSGlobalObject.cpp: Updated JSGlobalObject to support moving its
global storage area into and out of the register file.
* kjs/PropertySlot.cpp: No need to fiddle with the register file anymore.
* kjs/collector.cpp: Renamed markStackObjectConservatively to
markConservatively, since we don't just mark stack objects this way.
Also, added code to mark the machine's register file.
* kjs/config.h: Moved some platforms #defines from here...
* wtf/Platform.h: ...to here, to support mmap/VirtualAlloc detection
in RegisterFile.h.
2008-06-26 Mark Rowe <mrowe@apple.com>
Speculative fix for the Windows build.
......
......@@ -101,7 +101,6 @@ __ZN3KJS12DateInstance4infoE
__ZN3KJS12JSGlobalData14sharedInstanceEv
__ZN3KJS12JSGlobalData14threadInstanceEv
__ZN3KJS12PropertySlot15undefinedGetterEPNS_9ExecStateERKNS_10IdentifierERKS0_
__ZN3KJS12RegisterFile14addGlobalSlotsEm
__ZN3KJS12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE
__ZN3KJS12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
......@@ -131,12 +130,12 @@ __ZN3KJS16InternalFunction4infoE
__ZN3KJS16InternalFunctionC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
__ZN3KJS16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS16JSVariableObject16setRegisterArrayEPNS_8RegisterEm
__ZN3KJS16ParserRefCounted3refEv
__ZN3KJS16ParserRefCounted5derefEv
__ZN3KJS17PropertyNameArray3addEPNS_7UString3RepE
__ZN3KJS17PrototypeFunctionC1EPNS_9ExecStateEPNS_17FunctionPrototypeEiRKNS_10IdentifierEPFPNS_7JSValueES2_PNS_8JSObjectES9_RKNS_7ArgListEE
__ZN3KJS17PrototypeFunctionC1EPNS_9ExecStateEiRKNS_10IdentifierEPFPNS_7JSValueES2_PNS_8JSObjectES7_RKNS_7ArgListEE
__ZN3KJS17RegisterFileStack20allocateRegisterFileEmPS0_
__ZN3KJS17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
__ZN3KJS19constructEmptyArrayEPNS_9ExecStateE
__ZN3KJS19initializeThreadingEv
......@@ -181,6 +180,7 @@ __ZN3KJS7ArgList10slowAppendEPNS_7JSValueE
__ZN3KJS7CStringD1Ev
__ZN3KJS7CStringaSERKS0_
__ZN3KJS7JSArray4infoE
__ZN3KJS7Machine13dumpCallFrameEPKNS_9CodeBlockEPNS_14ScopeChainNodeEPNS_12RegisterFileEPKNS_8RegisterE
__ZN3KJS7Profile10restoreAllEv
__ZN3KJS7Profile5focusEPKNS_11ProfileNodeE
__ZN3KJS7Profile7excludeEPKNS_11ProfileNodeE
......
......@@ -99,8 +99,6 @@
14BD5A310A3E91F600BAF59C /* JSContextRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */; settings = {ATTRIBUTES = (Public, ); }; };
14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */; };
14D792660DAA03FB001A9F05 /* RegisterFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D792640DAA03FB001A9F05 /* RegisterFile.h */; settings = {ATTRIBUTES = (Private, ); }; };
14D797800DAC3307001A9F05 /* RegisterFileStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D7977E0DAC3307001A9F05 /* RegisterFileStack.h */; settings = {ATTRIBUTES = (Private, ); }; };
14D797810DAC3307001A9F05 /* RegisterFileStack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14D7977F0DAC3307001A9F05 /* RegisterFileStack.cpp */; };
14DA81900D99FD2000B0A4FB /* JSActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA818E0D99FD2000B0A4FB /* JSActivation.h */; };
14E0FF120DBAAED00007C0AB /* Machine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 149B15E70D81F986009CB8C7 /* Machine.cpp */; settings = {COMPILER_FLAGS = "-fno-tree-pre"; }; };
14F252570D08DD8D004ECFFF /* JSVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F252560D08DD8D004ECFFF /* JSVariableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -459,8 +457,6 @@
14BD5A2D0A3E91F600BAF59C /* testapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testapi.c; path = API/testapi.c; sourceTree = "<group>"; };
14D792640DAA03FB001A9F05 /* RegisterFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterFile.h; path = VM/RegisterFile.h; sourceTree = "<group>"; };
14D792650DAA03FB001A9F05 /* RegisterFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterFile.cpp; path = VM/RegisterFile.cpp; sourceTree = "<group>"; };
14D7977E0DAC3307001A9F05 /* RegisterFileStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterFileStack.h; path = VM/RegisterFileStack.h; sourceTree = "<group>"; };
14D7977F0DAC3307001A9F05 /* RegisterFileStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterFileStack.cpp; path = VM/RegisterFileStack.cpp; sourceTree = "<group>"; };
14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/testapi.js; sourceTree = "<group>"; };
14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; };
14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = "<group>"; };
......@@ -880,8 +876,6 @@
149B24FF0D8AF6D1009CB8C7 /* Register.h */,
14D792650DAA03FB001A9F05 /* RegisterFile.cpp */,
14D792640DAA03FB001A9F05 /* RegisterFile.h */,
14D7977F0DAC3307001A9F05 /* RegisterFileStack.cpp */,
14D7977E0DAC3307001A9F05 /* RegisterFileStack.h */,
A72701B30DADE94900E548D7 /* ExceptionHelpers.h */,
A72701B40DADE94900E548D7 /* ExceptionHelpers.cpp */,
);
......@@ -1052,8 +1046,8 @@
F692A86B0255597D01FF60F7 /* MathObject.h */,
F692A8700255597D01FF60F7 /* NumberObject.cpp */,
F692A8710255597D01FF60F7 /* NumberObject.h */,
F692A8750255597D01FF60F7 /* JSObject.cpp */,
F692A8760255597D01FF60F7 /* JSObject.h */,
F692A8750255597D01FF60F7 /* JSObject.cpp */,
F692A8730255597D01FF60F7 /* object_object.cpp */,
F692A8740255597D01FF60F7 /* object_object.h */,
F692A8770255597D01FF60F7 /* operations.cpp */,
......@@ -1308,7 +1302,6 @@
14DA81900D99FD2000B0A4FB /* JSActivation.h in Headers */,
145C50800D9DF63B0088F6B9 /* CallData.h in Headers */,
14D792660DAA03FB001A9F05 /* RegisterFile.h in Headers */,
14D797800DAC3307001A9F05 /* RegisterFileStack.h in Headers */,
BC8F3CED0DAF1A8000577A80 /* ConstructData.h in Headers */,
A72701B50DADE94900E548D7 /* ExceptionHelpers.h in Headers */,
A7C31DA90DBEBA4300FDF8EB /* SegmentedVector.h in Headers */,
......@@ -1599,7 +1592,6 @@
149B25020D8AF6D1009CB8C7 /* Register.cpp in Sources */,
A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */,
A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */,
14D797810DAC3307001A9F05 /* RegisterFileStack.cpp in Sources */,
A72701B60DADE94900E548D7 /* ExceptionHelpers.cpp in Sources */,
149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
E18E3A590DF9278C00D90B34 /* JSGlobalData.cpp in Sources */,
......
......@@ -148,7 +148,7 @@ void CodeGenerator::generate()
}
}
bool CodeGenerator::addVar(const Identifier& ident, RegisterID*& r0, bool isConstant)
bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
{
int index = m_nextVar;
SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
......@@ -167,13 +167,30 @@ bool CodeGenerator::addVar(const Identifier& ident, RegisterID*& r0, bool isCons
return result.second;
}
CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack, bool canCreateVariables)
bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
{
int index = m_nextVar;
SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
if (!result.second)
index = result.first->second.getIndex();
else {
--m_nextVar;
m_locals.append(index + m_globalVarStorageOffset);
}
r0 = &m_locals[localsIndex(index)];
return result.second;
}
CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack)
: m_shouldEmitDebugHooks(!!debugger)
, m_scopeChain(&scopeChain)
, m_symbolTable(symbolTable)
, m_scopeNode(programNode)
, m_codeBlock(codeBlock)
, m_thisRegister(Machine::ProgramCodeThisRegister)
, m_thisRegister(RegisterFile::ProgramCodeThisRegister)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_codeType(GlobalCode)
......@@ -182,34 +199,37 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
{
// Global code can inherit previously defined symbols.
int size = symbolTable->size() + 1; // + 1 slot for "this"
// FIXME: Move code that modifies the global object to Machine::execute.
m_codeBlock->numVars = 1; // Allocate space for "this"
JSGlobalObject* globalObject = scopeChain.globalObject();
ExecState* exec = globalObject->globalExec();
RegisterFile* registerFile = &exec->globalData().machine->registerFile();
// Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
// Add previously defined symbols to bookkeeping.
m_locals.resize(size);
m_locals.resize(symbolTable->size());
SymbolTable::iterator end = symbolTable->end();
for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex());
m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
// Shift new symbols so they get stored prior to previously defined symbols.
m_nextVar -= size;
bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
if (canOptimizeNewGlobals) {
// Shift new symbols so they get stored prior to existing symbols.
m_nextVar -= symbolTable->size();
JSGlobalObject* globalObject = scopeChain.globalObject();
ExecState* exec = globalObject->globalExec();
// FIXME: Move the execution-related parts of this code to Machine::execute.
if (canCreateVariables) {
for (size_t i = 0; i < functionStack.size(); ++i) {
FuncDeclNode* funcDecl = functionStack[i].get();
globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
emitNewFunction(addVar(funcDecl->m_ident, false), funcDecl);
emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
}
for (size_t i = 0; i < varStack.size(); ++i) {
if (!globalObject->hasProperty(exec, varStack[i].first))
emitLoad(addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
}
} else {
for (size_t i = 0; i < functionStack.size(); ++i) {
......@@ -255,9 +275,7 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
const Identifier& ident = varStack[i].first;
if (ident == propertyNames().arguments)
continue;
RegisterID* r0;
addVar(ident, r0, varStack[i].second & DeclarationStacks::IsConstant);
addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
}
Vector<Identifier>& parameters = functionBody->parameters();
......@@ -279,12 +297,11 @@ CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const
, m_symbolTable(symbolTable)
, m_scopeNode(evalNode)
, m_codeBlock(codeBlock)
, m_thisRegister(Machine::ProgramCodeThisRegister)
, m_thisRegister(RegisterFile::ProgramCodeThisRegister)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_codeType(EvalCode)
, m_continueDepth(0)
, m_nextVar(-1)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
{
......@@ -816,8 +833,8 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
RefPtr<RegisterID> refBase = base;
// Reserve space for call frame.
Vector<RefPtr<RegisterID>, Machine::CallFrameHeaderSize> callFrame;
for (int i = 0; i < Machine::CallFrameHeaderSize; ++i)
Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
callFrame.append(newTemporary());
// Generate code for arguments.
......@@ -847,8 +864,8 @@ RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode)
{
// Reserve space for call frame.
Vector<RefPtr<RegisterID>, Machine::CallFrameHeaderSize> callFrame;
for (int i = 0; i < Machine::CallFrameHeaderSize; ++i)
Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
callFrame.append(newTemporary());
// Generate code for arguments.
......
......@@ -76,7 +76,7 @@ namespace KJS {
static void setDumpsGeneratedCode(bool dumpsGeneratedCode);
CodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*, VarStack&, FunctionStack&, bool canCreateGlobals);
CodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*, VarStack&, FunctionStack&);
CodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*);
CodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*);
......@@ -312,12 +312,22 @@ namespace KJS {
RegisterID* addVar(const Identifier& ident, bool isConstant)
{
RegisterID* local;
addVar(ident, local, isConstant);
addVar(ident, isConstant, local);
return local;
}
// Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
bool addVar(const Identifier&, bool isConstant, RegisterID*&);
// Returns the RegisterID corresponding to ident.
RegisterID* addGlobalVar(const Identifier& ident, bool isConstant)
{
RegisterID* local;
addGlobalVar(ident, isConstant, local);
return local;
}
// Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
bool addVar(const Identifier&, RegisterID*&, bool isConstant);
bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&);
RegisterID* addParameter(const Identifier&);
......@@ -358,6 +368,8 @@ namespace KJS {
int m_nextVar;
int m_nextParameter;
int m_globalVarStorageOffset;
// Constant pool
IdentifierMap m_identifierMap;
JSValueMap m_jsValueMap;
......
This diff is collapsed.
......@@ -30,7 +30,7 @@
#define Machine_h
#include "Opcode.h"
#include "RegisterFileStack.h"
#include "RegisterFile.h"
#include <kjs/list.h>
#include <wtf/HashMap.h>
......@@ -40,10 +40,11 @@ namespace KJS {
class EvalNode;
class ExecState;
class FunctionBodyNode;
class Instruction;
class JSFunction;
class ProgramNode;
class Register;
class RegisterFile;
class RegisterFileStack;
class ScopeChainNode;
enum DebugHookID {
......@@ -59,24 +60,10 @@ namespace KJS {
class Machine {
public:
enum {
CallerCodeBlock = 0,
ReturnVPC,
CallerScopeChain,
CallerRegisterOffset,
ReturnValueRegister,
ArgumentStartRegister,
ArgumentCount,
CalledAsConstructor,
Callee,
OptionalCalleeActivation,
CallFrameHeaderSize
};
enum { ProgramCodeThisRegister = -1 };
Machine();
RegisterFile& registerFile() { return m_registerFile; }
Opcode getOpcode(OpcodeID id)
{
#if HAVE(COMPUTED_GOTO)
......@@ -97,20 +84,27 @@ namespace KJS {
}
bool isOpcode(Opcode opcode);
JSValue* execute(ProgramNode*, ExecState*, ScopeChainNode*, JSObject* thisObj, RegisterFileStack*, JSValue** exception);
JSValue* execute(FunctionBodyNode*, ExecState*, JSFunction*, JSObject* thisObj, const ArgList& args, RegisterFileStack*, ScopeChainNode*, JSValue** exception);
JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, RegisterFile*, int registerOffset, ScopeChainNode*, JSValue** exception);
JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, RegisterFileStack*, ScopeChainNode*, JSValue** exception);
JSValue* execute(ProgramNode*, ExecState*, ScopeChainNode*, JSObject* thisObj, JSValue** exception);
JSValue* execute(FunctionBodyNode*, ExecState*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue** exception);
JSValue* execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
{
return execute(evalNode, exec, thisObj, m_registerFile.size(), scopeChain, exception);
}
JSValue* retrieveArguments(ExecState*, JSFunction*) const;
JSValue* retrieveCaller(ExecState*, JSFunction*) const;
void getFunctionAndArguments(Register** registerBase, Register* callFrame, JSFunction*&, Register*& argv, int& argc);
void mark(Heap* heap) { m_registerFile.mark(heap); }
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
friend NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
NEVER_INLINE void debug(ExecState*, const Instruction*, const CodeBlock*, ScopeChainNode*, Register**, Register*);
......@@ -124,9 +118,9 @@ namespace KJS {
void dumpCallFrame(const CodeBlock*, ScopeChainNode*, RegisterFile*, const Register*);
void dumpRegisters(const CodeBlock*, RegisterFile*, const Register*);
bool isGlobalCallFrame(Register** registerBase, const Register* r) const { return (*registerBase) == r; }
int m_reentryDepth;
RegisterFile m_registerFile;
#if HAVE(COMPUTED_GOTO)
Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
......
......@@ -29,83 +29,18 @@
#include "config.h"
#include "RegisterFile.h"
#include "RegisterFileStack.h"
#include "Register.h"
using namespace std;
namespace KJS {
size_t RegisterFile::newBuffer(size_t size, size_t capacity, size_t minCapacity, size_t maxSize, size_t offset)
{
capacity = (max(minCapacity, min(maxSize, max<size_t>(16, capacity + capacity / 4 + 1))));
Register* newBuffer = static_cast<Register*>(fastCalloc(capacity, sizeof(Register))); // zero-filled memory
if (m_buffer)
memcpy(newBuffer + offset, m_buffer, size * sizeof(Register));
setBuffer(newBuffer);
return capacity;
}
bool RegisterFile::growBuffer(size_t minCapacity, size_t maxSize)
{
if (minCapacity > m_maxSize)
return false;
size_t numGlobalSlots = this->numGlobalSlots();
size_t size = m_size + numGlobalSlots;
size_t capacity = m_capacity + numGlobalSlots;
minCapacity += numGlobalSlots;
capacity = newBuffer(size, capacity, minCapacity, maxSize, 0);
setBase(m_buffer + numGlobalSlots);
m_capacity = capacity - numGlobalSlots;
return true;
}
void RegisterFile::addGlobalSlots(size_t count)
{
if (!count)
return;
ASSERT(safeForReentry());
size_t numGlobalSlots = this->numGlobalSlots();
size_t size = m_size + numGlobalSlots;
size_t capacity = m_capacity + numGlobalSlots;
size_t minCapacity = size + count;
if (minCapacity < capacity)
memmove(m_buffer + count, m_buffer, size * sizeof(Register));
else
capacity = newBuffer(size, capacity, minCapacity, m_maxSize, count);
numGlobalSlots += count;
setBase(m_buffer + numGlobalSlots);
m_capacity = capacity - numGlobalSlots;
}
void RegisterFile::copyGlobals(RegisterFile* src)
{
ASSERT(src->numGlobalSlots() > 0); // Global code should always allocate at least a "this" slot.
size_t numSlotsToCopy = src->numGlobalSlots() - 1; // Don't propogate the nested "this" value back to the parent register file.
if (!numSlotsToCopy)
return;
memcpy(m_buffer, src->m_buffer, numSlotsToCopy * sizeof(Register));
}
void RegisterFile::setBase(Register* base)
{
m_base = base;
if (m_baseObserver)
m_baseObserver->baseChanged(this);
}
void RegisterFile::clear()
RegisterFile::~RegisterFile()
{
setBase(m_buffer);
m_size = 0;
#if HAVE(MMAP)
munmap(m_buffer, m_capacity + m_maxGlobals);
#elif HAVE(VIRTUALALLOC)
// FIXME: Use VirtualFree.
fastFree(m_buffer);
#else
#error "Don't know how to release virtual memory on this platform."
#endif
}
} // namespace KJS
......@@ -31,6 +31,9 @@
#include "Register.h"
#include "collector.h"
#if HAVE(MMAP)
#include <sys/mman.h>
#endif
#include <wtf/Noncopyable.h>
namespace KJS {
......@@ -82,30 +85,57 @@ namespace KJS {
"base", not "buffer".
*/
class RegisterFileStack;
class JSGlobalObject;
class RegisterFile : Noncopyable {
public:
enum { DefaultRegisterFileSize = 2 * 1024 * 1024 };
RegisterFile(size_t maxSize, RegisterFileStack* m_baseObserver)
: m_safeForReentry(true)
, m_size(0)
, m_capacity(0)
, m_maxSize(maxSize)
enum {
CallerCodeBlock = 0,
ReturnVPC,
CallerScopeChain,
CallerRegisterOffset,
ReturnValueRegister,
ArgumentStartRegister,
ArgumentCount,
CalledAsConstructor,
Callee,
OptionalCalleeActivation,
CallFrameHeaderSize
};
enum { ProgramCodeThisRegister = - 1 };
enum { DefaultCapacity = 2 * 1024 * 1024 };
enum { DefaultMaxGlobals = 8 * 1024 };
RegisterFile(size_t capacity = DefaultCapacity, size_t maxGlobals = DefaultMaxGlobals)
: m_size(0)
, m_capacity(capacity)
, m_numGlobals(0)
, m_maxGlobals(maxGlobals)
, m_base(0)
, m_buffer(0)
, m_baseObserver(m_baseObserver)
, 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));
#elif HAVE(VIRTUALALLOC)
// FIXME: Use VirtualAlloc, and commit pages as we go.
m_buffer = fastMalloc(bufferLength);
#else
#error "Don't know how to reserve virtual memory on this platform."
#endif
m_base = m_buffer + maxGlobals;
}
~RegisterFile()
{
setBuffer(0);
}
~RegisterFile();
// Pointer to a value that holds the base of this register file.
Register** basePointer() { return &m_base; }
void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; }
JSGlobalObject* globalObject() { return m_globalObject; }
void shrink(size_t size)
{
......@@ -116,56 +146,37 @@ namespace KJS {
bool grow(size_t size)
{
if (size > m_size) {
if (size > m_capacity) {
if (size > m_maxSize)
return false;
growBuffer(size, m_maxSize);
}
if (size > m_capacity)
return false;
#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
// FIXME: Use VirtualAlloc, and commit pages as we go.
#endif
m_size = size;
}
return true;
}
size_t size() { return m_size; }
size_t maxSize() { return m_maxSize; }
void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
int numGlobals() { return m_numGlobals; }