Commit 75f804e0 authored by oliver@apple.com's avatar oliver@apple.com

Bring back eager resolution of function scoped variables

https://bugs.webkit.org/show_bug.cgi?id=111497

Reviewed by Geoffrey Garen.

This reverts the get/put_scoped_var part of the great non-local
variable resolution refactoring.  This still leaves all the lazy
variable resolution logic as it's necessary for global property
resolution, and i don't want to make the patch bigger than it
already is.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(UnlinkedFunctionExecutable):
(UnlinkedCodeBlock):
(JSC::UnlinkedCodeBlock::usesGlobalObject):
(JSC::UnlinkedCodeBlock::setGlobalObjectRegister):
(JSC::UnlinkedCodeBlock::globalObjectRegister):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ResolveResult::checkValidity):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):
* bytecompiler/BytecodeGenerator.h:
(JSC::ResolveResult::lexicalResolve):
(JSC::ResolveResult::isStatic):
(JSC::ResolveResult::depth):
(JSC::ResolveResult::index):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::debugFail):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
* runtime/CodeCache.h:
(JSC):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/Options.cpp:
(JSC::Options::initialize):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@145000 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ffd46d7d
2013-03-05 Oliver Hunt <oliver@apple.com>
Bring back eager resolution of function scoped variables
https://bugs.webkit.org/show_bug.cgi?id=111497
Reviewed by Geoffrey Garen.
This reverts the get/put_scoped_var part of the great non-local
variable resolution refactoring. This still leaves all the lazy
variable resolution logic as it's necessary for global property
resolution, and i don't want to make the patch bigger than it
already is.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(UnlinkedFunctionExecutable):
(UnlinkedCodeBlock):
(JSC::UnlinkedCodeBlock::usesGlobalObject):
(JSC::UnlinkedCodeBlock::setGlobalObjectRegister):
(JSC::UnlinkedCodeBlock::globalObjectRegister):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ResolveResult::checkValidity):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):
* bytecompiler/BytecodeGenerator.h:
(JSC::ResolveResult::lexicalResolve):
(JSC::ResolveResult::isStatic):
(JSC::ResolveResult::depth):
(JSC::ResolveResult::index):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::debugFail):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_scoped_var):
(JSC):
(JSC::JIT::emit_op_put_scoped_var):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
* runtime/CodeCache.h:
(JSC):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/Options.cpp:
(JSC::Options::initialize):
2013-03-06 Filip Pizlo <fpizlo@apple.com>
Unreviewed, roll out http://trac.webkit.org/changeset/144989
......
......@@ -980,6 +980,21 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_get_scoped_var: {
int r0 = (++it)->u.operand;
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
out.printf("[%4d] get_scoped_var\t %s, %d, %d", location, registerName(exec, r0).data(), index, skipLevels);
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
case op_put_scoped_var: {
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
int r0 = (++it)->u.operand;
out.printf("[%4d] put_scoped_var\t %d, %d, %s", location, index, skipLevels, registerName(exec, r0).data());
break;
}
case op_init_global_const_nop: {
out.printf("[%4d] init_global_const_nop\t", location);
it++;
......@@ -1644,8 +1659,10 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
, m_argumentsRegister(other.m_argumentsRegister)
, m_activationRegister(other.m_activationRegister)
, m_isStrictMode(other.m_isStrictMode)
, m_needsActivation(other.m_needsActivation)
, m_source(other.m_source)
, m_sourceOffset(other.m_sourceOffset)
, m_codeType(other.m_codeType)
, m_identifiers(other.m_identifiers)
, m_constantRegisters(other.m_constantRegisters)
, m_functionDecls(other.m_functionDecls)
......@@ -1687,8 +1704,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
, m_argumentsRegister(unlinkedCodeBlock->argumentsRegister())
, m_activationRegister(unlinkedCodeBlock->activationRegister())
, m_isStrictMode(unlinkedCodeBlock->isStrictMode())
, m_needsActivation(unlinkedCodeBlock->needsFullScopeChain())
, m_source(sourceProvider)
, m_sourceOffset(sourceOffset)
, m_codeType(unlinkedCodeBlock->codeType())
, m_alternative(alternative)
, m_osrExitCounter(0)
, m_optimizationDelayCounter(0)
......@@ -1704,7 +1723,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
#endif
setIdentifiers(unlinkedCodeBlock->identifiers());
setConstantRegisters(unlinkedCodeBlock->constantRegisters());
if (unlinkedCodeBlock->usesGlobalObject())
m_constantRegisters[unlinkedCodeBlock->globalObjectRegister()].set(*m_globalData, ownerExecutable, globalObject);
m_functionDecls.grow(unlinkedCodeBlock->numberOfFunctionDecls());
for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) {
UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i);
......@@ -1920,6 +1940,16 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
break;
}
case op_get_scoped_var: {
#if ENABLE(DFG_JIT)
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
instructions[i + opLength - 1] = profile;
#endif
break;
}
case op_call:
case op_call_eval: {
#if ENABLE(DFG_JIT)
......
......@@ -532,7 +532,7 @@ namespace JSC {
{
return needsFullScopeChain() && codeType() != GlobalCode;
}
bool isCaptured(int operand, InlineCallFrame* inlineCallFrame = 0) const
{
if (operandIsArgument(operand))
......@@ -1155,9 +1155,11 @@ namespace JSC {
int m_activationRegister;
bool m_isStrictMode;
bool m_needsActivation;
RefPtr<SourceProvider> m_source;
unsigned m_sourceOffset;
unsigned m_codeType;
#if ENABLE(LLINT)
SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos;
......
......@@ -97,6 +97,9 @@ namespace JSC {
macro(op_is_function, 3) \
macro(op_in, 4) \
\
macro(op_get_scoped_var, 5) /* has value profiling */ \
macro(op_put_scoped_var, 4) \
\
macro(op_resolve, 5) /* has value profiling */ \
macro(op_resolve_global_property, 5) /* has value profiling */ \
macro(op_resolve_global_var, 5) /* has value profiling */ \
......
......@@ -47,7 +47,7 @@ const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock",
const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& globalData, JSScope* scope, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&globalData, source, executable->parameters(), executable->name(), executable->isInStrictContext() ? JSParseStrict : JSParseNormal, JSParseFunctionCode, error);
......@@ -62,7 +62,7 @@ static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData& global
executable->recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&globalData, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, body.get(), result, debuggerMode, profilerMode)));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, scope, body.get(), result, debuggerMode, profilerMode)));
error = generator->generate();
body->destroyData();
if (error.m_type != ParserError::ErrorNone)
......@@ -139,7 +139,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Ide
return executable;
}
UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData& globalData, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData& globalData, JSScope* scope, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
switch (specializationKind) {
case CodeForCall:
......@@ -152,7 +152,7 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData
break;
}
UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(globalData, this, source, specializationKind, debuggerMode, profilerMode, error);
UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(globalData, scope, this, source, specializationKind, debuggerMode, profilerMode, error);
if (error.m_type != ParserError::ErrorNone)
return 0;
......@@ -189,6 +189,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct
, m_numParameters(0)
, m_globalData(globalData)
, m_argumentsRegister(-1)
, m_globalObjectRegister(-1)
, m_needsFullScopeChain(info.m_needsActivation)
, m_usesEval(info.m_usesEval)
, m_isNumericCompareFunction(false)
......
......@@ -49,6 +49,7 @@ class Debugger;
class FunctionBodyNode;
class FunctionExecutable;
class FunctionParameters;
class JSScope;
struct ParserError;
class ScriptExecutable;
class SourceCode;
......@@ -107,7 +108,7 @@ public:
String paramString() const;
UnlinkedFunctionCodeBlock* codeBlockFor(JSGlobalData&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionCodeBlock* codeBlockFor(JSGlobalData&, JSScope*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
static UnlinkedFunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
......@@ -268,6 +269,11 @@ public:
bool usesArguments() const { return m_argumentsRegister != -1; }
int argumentsRegister() const { return m_argumentsRegister; }
bool usesGlobalObject() const { return m_globalObjectRegister != -1; }
void setGlobalObjectRegister(int globalObjectRegister) { m_globalObjectRegister = globalObjectRegister; }
int globalObjectRegister() const { return m_globalObjectRegister; }
// Parameter information
void setNumParameters(int newValue) { m_numParameters = newValue; }
void addParameter() { m_numParameters++; }
......@@ -493,6 +499,7 @@ private:
int m_thisRegister;
int m_argumentsRegister;
int m_activationRegister;
int m_globalObjectRegister;
bool m_needsFullScopeChain : 1;
bool m_usesEval : 1;
......
......@@ -128,14 +128,22 @@ namespace JSC {
DynamicFlag = 0x2,
// The resolved binding is immutable.
ReadOnlyFlag = 0x4,
// The property has a static location
StaticFlag = 0x8,
// Entry at scope distance "m_depth" and located at "m_index"
ScopedFlag = 0x10
};
enum Type {
// The property is local, and stored in a register.
Register = RegisterFlag,
Register = RegisterFlag | StaticFlag,
// A read-only local, created by "const".
ReadOnlyRegister = RegisterFlag | ReadOnlyFlag,
// Any form of non-local lookup
ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
// Lexically fixed location in the scope chain
Lexical = ScopedFlag | StaticFlag,
// A read-only Lexical, created by "const".
ReadOnlyLexical = ScopedFlag | ReadOnlyFlag | StaticFlag,
// Any other form of lookup
Dynamic = DynamicFlag,
};
......@@ -147,6 +155,12 @@ namespace JSC {
{
return ResolveResult(Dynamic, 0);
}
static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
{
if (flags & DynamicFlag)
return dynamicResolve();
return ResolveResult(Lexical | flags, index, depth);
}
unsigned type() const { return m_type; }
// Returns the register corresponding to a local variable, or 0 if no
......@@ -155,13 +169,30 @@ namespace JSC {
RegisterID* local() const { return m_local; }
bool isRegister() const { return m_type & RegisterFlag; }
bool isStatic() const { return (m_type & StaticFlag) && !isDynamic(); }
bool isDynamic() const { return m_type & DynamicFlag; }
bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
unsigned depth() const { ASSERT(isStatic()); return m_depth; }
int32_t index() const { ASSERT(isStatic()); return m_index; }
private:
ResolveResult(unsigned type, RegisterID* local)
: m_type(type)
, m_local(local)
, m_index(0)
, m_depth(0)
{
#ifndef NDEBUG
checkValidity();
#endif
}
ResolveResult(unsigned type, int index, unsigned depth)
: m_type(type)
, m_local(0)
, m_index(index)
, m_depth(depth)
{
#ifndef NDEBUG
checkValidity();
......@@ -174,6 +205,8 @@ namespace JSC {
unsigned m_type;
RegisterID* m_local; // Local register, if RegisterFlag is set
int m_index;
unsigned m_depth;
};
struct NonlocalResolveInfo {
......@@ -211,9 +244,9 @@ namespace JSC {
typedef DeclarationStacks::VarStack VarStack;
typedef DeclarationStacks::FunctionStack FunctionStack;
BytecodeGenerator(JSGlobalData&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode);
BytecodeGenerator(JSGlobalData&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode);
BytecodeGenerator(JSGlobalData&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode);
BytecodeGenerator(JSGlobalData&, JSScope*, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode);
BytecodeGenerator(JSGlobalData&, JSScope*, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode);
BytecodeGenerator(JSGlobalData&, JSScope*, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode);
~BytecodeGenerator();
......@@ -379,6 +412,7 @@ namespace JSC {
RegisterID* emitLoad(RegisterID* dst, double);
RegisterID* emitLoad(RegisterID* dst, const Identifier&);
RegisterID* emitLoad(RegisterID* dst, JSValue);
RegisterID* emitLoadGlobalObject(RegisterID* dst);
RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
......@@ -408,7 +442,8 @@ namespace JSC {
RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
RegisterID* emitGetLocalVar(RegisterID* dst, const ResolveResult&, const Identifier&);
RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&);
RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value);
RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
......@@ -650,6 +685,7 @@ namespace JSC {
SharedSymbolTable* m_symbolTable;
ScopeNode* m_scopeNode;
Strong<JSScope> m_scope;
Strong<UnlinkedCodeBlock> m_codeBlock;
// Some of these objects keep pointers to one another. They are arranged
......@@ -660,6 +696,7 @@ namespace JSC {
RegisterID m_calleeRegister;
RegisterID* m_activationRegister;
RegisterID* m_emptyValueRegister;
RegisterID* m_globalObjectRegister;
SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
SegmentedVector<RegisterID, 32> m_calleeRegisters;
SegmentedVector<RegisterID, 32> m_parameters;
......
......@@ -141,7 +141,7 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst
bool ResolveNode::isPure(BytecodeGenerator& generator) const
{
return generator.resolve(m_ident).isRegister();
return generator.resolve(m_ident).isStatic();
}
RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
......@@ -439,6 +439,14 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
if (resolveResult.isStatic()) {
RefPtr<RegisterID> func = generator.newTemporary();
CallArguments callArguments(generator, m_args);
generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
}
RefPtr<RegisterID> func = generator.newTemporary();
CallArguments callArguments(generator, m_args);
int identifierStart = divot() - startOffset();
......@@ -622,7 +630,19 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
return emitPreIncOrDec(generator, local, m_operator);
return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
RegisterID* oldValue;
if (dst == generator.ignoredResult()) {
oldValue = 0;
emitPreIncOrDec(generator, value.get(), m_operator);
} else
oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
generator.emitPutStaticVar(resolveResult, ident, value.get());
return oldValue;
}
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> value = generator.newTemporary();
NonlocalResolveInfo resolveInfo;
......@@ -767,6 +787,11 @@ RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
return generator.emitTypeOf(generator.finalDestination(dst), local);
}
if (resolveResult.isStatic()) {
RefPtr<RegisterID> scratch = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get());
}
RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident);
generator.emitGetById(scratch.get(), scratch.get(), m_ident);
if (dst == generator.ignoredResult())
......@@ -808,6 +833,13 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
return generator.moveToDestinationIfNeeded(dst, local);
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
emitPreIncOrDec(generator, propDst.get(), m_operator);
generator.emitPutStaticVar(resolveResult, ident, propDst.get());
return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RefPtr<RegisterID> propDst = generator.tempDestination(dst);
NonlocalResolveInfo resolveVerifier;
......@@ -1267,6 +1299,13 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
return generator.moveToDestinationIfNeeded(dst, result);
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
generator.emitPutStaticVar(resolveResult, m_ident, result);
return result;
}
RefPtr<RegisterID> src1 = generator.tempDestination(dst);
generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
NonlocalResolveInfo resolveVerifier;
......@@ -1290,6 +1329,14 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
return generator.moveToDestinationIfNeeded(dst, result);
}
if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
generator.emitPutStaticVar(resolveResult, m_ident, value);
return value;
}
NonlocalResolveInfo resolveVerifier;
RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
if (dst == generator.ignoredResult())
......@@ -1391,10 +1438,9 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
if (generator.codeType() == GlobalCode) {
if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get()))
return result;
}
if (generator.codeType() == GlobalCode)
return generator.emitInitGlobalConst(m_ident, value.get());
if (generator.codeType() != EvalCode)
return value.get();
......
......@@ -3064,6 +3064,32 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr)));
LAST_OPCODE(op_jneq_ptr);
case op_get_scoped_var: {
SpeculatedType prediction = getPrediction();
int dst = currentInstruction[1].u.operand;
int slot = currentInstruction[2].u.operand;
int depth = currentInstruction[3].u.operand;
bool hasTopScope = m_codeBlock->codeType() == FunctionCode && m_inlineStackTop->m_codeBlock->needsFullScopeChain();
ASSERT(!hasTopScope || depth >= 1);
Node* scope = getScope(hasTopScope, depth - hasTopScope);
Node* getScopeRegisters = addToGraph(GetScopeRegisters, scope);
Node* getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeRegisters);
set(dst, getScopedVar);
NEXT_OPCODE(op_get_scoped_var);
}
case op_put_scoped_var: {
int slot = currentInstruction[1].u.operand;
int depth = currentInstruction[2].u.operand;
int source = currentInstruction[3].u.operand;
bool hasTopScope = m_codeBlock->codeType() == FunctionCode && m_inlineStackTop->m_codeBlock->needsFullScopeChain();
ASSERT(!hasTopScope || depth >= 1);
Node* scope = getScope(hasTopScope, depth - hasTopScope);
Node* scopeRegisters = addToGraph(GetScopeRegisters, scope);
addToGraph(PutScopedVar, OpInfo(slot), scope, scopeRegisters, get(source));
NEXT_OPCODE(op_put_scoped_var);
}
case op_resolve:
case op_resolve_global_property:
case op_resolve_global_var:
......
......@@ -85,7 +85,6 @@ static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, Capability
if (result == CannotCompile)
dataLogF("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
else {
ASSERT(result == ShouldProfile);
dataLogF("Cannot compile code block %p because of opcode %s, but inlining might be possible.\n", codeBlock, opcodeNames[opcodeID]);
}
#else
......
......@@ -203,6 +203,10 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
case op_resolve_scoped_var_with_top_scope_check:
return CanCompile;
case op_get_scoped_var:
case op_put_scoped_var:
return CanCompile;
case op_resolve_base_to_global:
case op_resolve_base_to_global_dynamic:
case op_resolve_base_to_scope:
......@@ -236,7 +240,11 @@ inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction
case op_resolve_with_base:
case op_resolve_with_this:
return canInlineResolveOperations(pc[4].u.resolveOperations);
case op_get_scoped_var:
case op_put_scoped_var:
return !codeBlock->needsFullScopeChain();
// Inlining doesn't correctly remap regular expression operands.
case op_new_regexp:
......
......@@ -390,6 +390,9 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_to_jsnumber)
DEFINE_OP(op_to_primitive)
DEFINE_OP(op_get_scoped_var)
DEFINE_OP(op_put_scoped_var)
case op_get_by_id_chain:
case op_get_by_id_generic:
case op_get_by_id_proto:
......
......@@ -756,6 +756,8 @@ namespace JSC {
void emit_op_to_primitive(Instruction*);
void emit_op_unexpected_load(Instruction*);
void emit_op_urshift(Instruction*);
void emit_op_get_scoped_var(Instruction*);
void emit_op_put_scoped_var(Instruction*);
void emitSlow_op_add(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_bitand(Instruction*, Vector<SlowCaseEntry>::iterator&);
......
......@@ -1204,6 +1204,54 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
}
void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
{
int skip = currentInstruction[3].u.operand;
emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT0);
bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
ASSERT(skip || !checkTopLevel);
if (checkTopLevel && skip--) {
Jump activationNotCreated;
if (checkTopLevel)
activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
activationNotCreated.link(this);
}
while (skip--)
loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
loadPtr(Address(regT0, JSVariableObject::offsetOfRegisters()), regT0);
loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0);
emitValueProfilingSite();
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
{
int skip = currentInstruction[2].u.operand;
emitGetVirtualRegister(currentInstruction[3].u.operand, regT0);
emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1);
bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
ASSERT(skip || !checkTopLevel);