#include "BytecodeGenerator.h"
#include "BatchedTransitionOptimizer.h"
+#include "PrototypeFunction.h"
#include "JSFunction.h"
#include "Interpreter.h"
#include "UString.h"
return result.second;
}
-void BytecodeGenerator::allocateConstants(size_t count)
+void BytecodeGenerator::preserveLastVar()
{
- m_codeBlock->m_numConstants = count;
- if (!count)
- return;
-
- m_nextConstantIndex = m_calleeRegisters.size();
-
- for (size_t i = 0; i < count; ++i)
- newRegister();
- m_lastConstant = &m_calleeRegisters.last();
+ if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0)
+ m_lastVar = &m_calleeRegisters.last();
}
BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock)
, m_baseScopeDepth(0)
, m_codeType(GlobalCode)
, m_nextGlobalIndex(-1)
+ , m_nextConstantOffset(0)
+ , m_globalConstantIndex(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
, m_emitNodeDepth(0)
m_nextGlobalIndex -= symbolTable->size();
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(addGlobalVar(funcDecl->m_ident, false), funcDecl);
+ FunctionBodyNode* function = functionStack[i];
+ globalObject->removeDirect(function->ident()); // Make sure our new function is not shadowed by an old property.
+ emitNewFunction(addGlobalVar(function->ident(), false), function);
}
Vector<RegisterID*, 32> newVars;
for (size_t i = 0; i < varStack.size(); ++i)
- if (!globalObject->hasProperty(exec, varStack[i].first))
- newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
+ if (!globalObject->hasProperty(exec, *varStack[i].first))
+ newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
- allocateConstants(programNode->neededConstants());
+ preserveLastVar();
for (size_t i = 0; i < newVars.size(); ++i)
emitLoad(newVars[i], jsUndefined());
} else {
for (size_t i = 0; i < functionStack.size(); ++i) {
- FuncDeclNode* funcDecl = functionStack[i].get();
- globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
+ FunctionBodyNode* function = functionStack[i];
+ globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain.node()), DontDelete);
}
for (size_t i = 0; i < varStack.size(); ++i) {
- if (globalObject->hasProperty(exec, varStack[i].first))
+ if (globalObject->hasProperty(exec, *varStack[i].first))
continue;
int attributes = DontDelete;
if (varStack[i].second & DeclarationStacks::IsConstant)
attributes |= ReadOnly;
- globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
+ globalObject->putWithAttributes(exec, *varStack[i].first, jsUndefined(), attributes);
}
- allocateConstants(programNode->neededConstants());
+ preserveLastVar();
}
}
, m_dynamicScopeDepth(0)
, m_baseScopeDepth(0)
, m_codeType(FunctionCode)
+ , m_nextConstantOffset(0)
+ , m_globalConstantIndex(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
, m_emitNodeDepth(0)
} else
emitOpcode(op_enter);
- if (usesArguments)
- emitOpcode(op_create_arguments);
+ if (usesArguments) {
+ emitOpcode(op_init_arguments);
+
+ // The debugger currently retrieves the arguments object from an activation rather than pulling
+ // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>),
+ // but for now we force eager creation of the arguments object when debugging.
+ if (m_shouldEmitDebugHooks)
+ emitOpcode(op_create_arguments);
+ }
const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
for (size_t i = 0; i < functionStack.size(); ++i) {
- FuncDeclNode* funcDecl = functionStack[i].get();
- const Identifier& ident = funcDecl->m_ident;
+ FunctionBodyNode* function = functionStack[i];
+ const Identifier& ident = function->ident();
m_functions.add(ident.ustring().rep());
- emitNewFunction(addVar(ident, false), funcDecl);
+ emitNewFunction(addVar(ident, false), function);
}
const DeclarationStacks::VarStack& varStack = functionBody->varStack();
for (size_t i = 0; i < varStack.size(); ++i)
- addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
+ addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
- const Identifier* parameters = functionBody->parameters();
- size_t parameterCount = functionBody->parameterCount();
+ FunctionParameters& parameters = *functionBody->parameters();
+ size_t parameterCount = parameters.size();
m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
m_parameters.grow(1 + parameterCount); // reserve space for "this"
for (size_t i = 0; i < parameterCount; ++i)
addParameter(parameters[i]);
- allocateConstants(functionBody->neededConstants());
+ preserveLastVar();
}
BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
, m_dynamicScopeDepth(0)
, m_baseScopeDepth(codeBlock->baseScopeDepth())
, m_codeType(EvalCode)
+ , m_nextConstantOffset(0)
+ , m_globalConstantIndex(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
, m_emitNodeDepth(0)
codeBlock->setGlobalData(m_globalData);
m_codeBlock->m_numParameters = 1; // Allocate space for "this"
- allocateConstants(evalNode->neededConstants());
+ const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
+ for (size_t i = 0; i < functionStack.size(); ++i)
+ m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
+
+ const DeclarationStacks::VarStack& varStack = evalNode->varStack();
+ unsigned numVariables = varStack.size();
+ Vector<Identifier> variables;
+ variables.reserveCapacity(numVariables);
+ for (size_t i = 0; i < numVariables; ++i)
+ variables.append(*varStack[i].first);
+ codeBlock->adoptVariables(variables);
+
+ preserveLastVar();
}
RegisterID* BytecodeGenerator::addParameter(const Identifier& ident)
if (entry.isNull())
return 0;
+ if (ident == propertyNames().arguments)
+ createArgumentsIfNecessary();
+
+ return ®isterFor(entry.getIndex());
+}
+
+bool BytecodeGenerator::willResolveToArguments(const Identifier& ident)
+{
+ if (ident != propertyNames().arguments)
+ return false;
+
+ if (!shouldOptimizeLocals())
+ return false;
+
+ SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
+ if (entry.isNull())
+ return false;
+
+ if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
+ return true;
+
+ return false;
+}
+
+RegisterID* BytecodeGenerator::uncheckedRegisterForArguments()
+{
+ ASSERT(willResolveToArguments(propertyNames().arguments));
+
+ SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.ustring().rep());
+ ASSERT(!entry.isNull());
return ®isterFor(entry.getIndex());
}
return 0;
SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
- ASSERT(!entry.isNull());
+ if (entry.isNull())
+ return 0;
return ®isterFor(entry.getIndex());
}
m_labelScopes.removeLast();
// Allocate new label scope.
- LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : 0); // Only loops have continue targets.
+ LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets.
m_labelScopes.append(scope);
return &m_labelScopes.last();
}
PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target)
{
+ size_t begin = instructions().size();
emitOpcode(target->isForward() ? op_jmp : op_loop);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target)
{
- if (m_lastOpcodeID == op_less && !target->isForward()) {
+ if (m_lastOpcodeID == op_less) {
int dstIndex;
int src1Index;
int src2Index;
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindBinaryOp();
- emitOpcode(op_loop_if_less);
+
+ size_t begin = instructions().size();
+ emitOpcode(target->isForward() ? op_jless : op_loop_if_less);
instructions().append(src1Index);
instructions().append(src2Index);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
} else if (m_lastOpcodeID == op_lesseq && !target->isForward()) {
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindBinaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_loop_if_lesseq);
instructions().append(src1Index);
instructions().append(src2Index);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
} else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindUnaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_jeq_null);
instructions().append(srcIndex);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
} else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindUnaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_jneq_null);
instructions().append(srcIndex);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
}
+ size_t begin = instructions().size();
+
emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
instructions().append(cond->index());
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target)
{
- ASSERT(target->isForward());
-
- if (m_lastOpcodeID == op_less) {
+ if (m_lastOpcodeID == op_less && target->isForward()) {
int dstIndex;
int src1Index;
int src2Index;
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindBinaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_jnless);
instructions().append(src1Index);
instructions().append(src2Index);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
+ return target;
+ }
+ } else if (m_lastOpcodeID == op_lesseq && target->isForward()) {
+ int dstIndex;
+ int src1Index;
+ int src2Index;
+
+ retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
+
+ if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
+ rewindBinaryOp();
+
+ size_t begin = instructions().size();
+ emitOpcode(op_jnlesseq);
+ instructions().append(src1Index);
+ instructions().append(src2Index);
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
} else if (m_lastOpcodeID == op_not) {
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindUnaryOp();
- emitOpcode(op_jtrue);
+
+ size_t begin = instructions().size();
+ emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
instructions().append(srcIndex);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
- } else if (m_lastOpcodeID == op_eq_null) {
+ } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
int dstIndex;
int srcIndex;
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindUnaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_jneq_null);
instructions().append(srcIndex);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
- } else if (m_lastOpcodeID == op_neq_null) {
+ } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
int dstIndex;
int srcIndex;
if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
rewindUnaryOp();
+
+ size_t begin = instructions().size();
emitOpcode(op_jeq_null);
instructions().append(srcIndex);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
}
- emitOpcode(op_jfalse);
+ size_t begin = instructions().size();
+ emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false);
instructions().append(cond->index());
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
-unsigned BytecodeGenerator::addConstant(FuncDeclNode* n)
+PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target)
{
- // No need to explicitly unique function body nodes -- they're unique already.
- return m_codeBlock->addFunction(n);
+ size_t begin = instructions().size();
+
+ emitOpcode(op_jneq_ptr);
+ instructions().append(cond->index());
+ instructions().append(m_scopeChain->globalObject()->d()->callFunction);
+ instructions().append(target->bind(begin, instructions().size()));
+ return target;
}
-unsigned BytecodeGenerator::addConstant(FuncExprNode* n)
+PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target)
{
- // No need to explicitly unique function expression nodes -- they're unique already.
- return m_codeBlock->addFunctionExpression(n);
+ size_t begin = instructions().size();
+
+ emitOpcode(op_jneq_ptr);
+ instructions().append(cond->index());
+ instructions().append(m_scopeChain->globalObject()->d()->applyFunction);
+ instructions().append(target->bind(begin, instructions().size()));
+ return target;
}
unsigned BytecodeGenerator::addConstant(const Identifier& ident)
return result.first->second;
}
-RegisterID* BytecodeGenerator::addConstant(JSValuePtr v)
+RegisterID* BytecodeGenerator::addConstantValue(JSValue v)
{
- pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValuePtr::encode(v), m_nextConstantIndex);
- if (result.second) {
- RegisterID& constant = m_calleeRegisters[m_nextConstantIndex];
-
- ++m_nextConstantIndex;
-
- m_codeBlock->addConstantRegister(JSValuePtr(v));
- return &constant;
- }
+ int index = m_nextConstantOffset;
- return ®isterFor(result.first->second);
-}
+ pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset);
+ if (result.second) {
+ m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
+ ++m_nextConstantOffset;
+ m_codeBlock->addConstantRegister(JSValue(v));
+ } else
+ index = result.first->second;
-unsigned BytecodeGenerator::addUnexpectedConstant(JSValuePtr v)
-{
- return m_codeBlock->addUnexpectedConstant(v);
+ return &m_constantPoolRegisters[index];
}
unsigned BytecodeGenerator::addRegExp(RegExp* r)
instructions().append(src2->index());
if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor ||
- opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub) {
+ opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div)
instructions().append(types.toInt());
- }
return dst;
}
if (src1->index() == dstIndex
&& src1->isTemporary()
&& m_codeBlock->isConstantRegisterIndex(src2->index())
- && m_codeBlock->constantRegister(src2->index() - m_codeBlock->m_numVars).jsValue(m_scopeChain->globalObject()->globalExec()).isString()) {
- const UString& value = asString(m_codeBlock->constantRegister(src2->index() - m_codeBlock->m_numVars).jsValue(m_scopeChain->globalObject()->globalExec()))->value();
+ && m_codeBlock->constantRegister(src2->index()).jsValue().isString()) {
+ const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->tryGetValue();
if (value == "undefined") {
rewindUnaryOp();
emitOpcode(op_is_undefined);
// Later we can do the extra work to handle that like the other cases.
if (number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
return emitLoad(dst, jsNumber(globalData(), number));
- JSValuePtr& valueInMap = m_numberMap.add(number, noValue()).first->second;
+ JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second;
if (!valueInMap)
valueInMap = jsNumber(globalData(), number);
return emitLoad(dst, valueInMap);
JSString*& stringInMap = m_stringMap.add(identifier.ustring().rep(), 0).first->second;
if (!stringInMap)
stringInMap = jsOwnedString(globalData(), identifier.ustring());
- return emitLoad(dst, JSValuePtr(stringInMap));
+ return emitLoad(dst, JSValue(stringInMap));
}
-RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValuePtr v)
+RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
{
- RegisterID* constantID = addConstant(v);
+ RegisterID* constantID = addConstantValue(v);
if (dst)
return emitMove(dst, constantID);
return constantID;
}
-RegisterID* BytecodeGenerator::emitUnexpectedLoad(RegisterID* dst, bool b)
-{
- emitOpcode(op_unexpected_load);
- instructions().append(dst->index());
- instructions().append(addUnexpectedConstant(jsBoolean(b)));
- return dst;
-}
-
-RegisterID* BytecodeGenerator::emitUnexpectedLoad(RegisterID* dst, double d)
-{
- emitOpcode(op_unexpected_load);
- instructions().append(dst->index());
- instructions().append(addUnexpectedConstant(jsNumber(globalData(), d)));
- return dst;
-}
-
bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, JSObject*& globalObject)
{
// Cases where we cannot statically optimize the lookup.
return dst;
}
-RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValuePtr globalObject)
+RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject)
{
if (globalObject) {
emitOpcode(op_get_global_var);
return dst;
}
-RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValuePtr globalObject)
+RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject)
{
if (globalObject) {
emitOpcode(op_put_global_var);
RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
{
- emitOpcode(op_resolve_base);
- instructions().append(dst->index());
- instructions().append(addConstant(property));
- return dst;
+ size_t depth = 0;
+ int index = 0;
+ JSObject* globalObject = 0;
+ findScopedProperty(property, index, depth, false, globalObject);
+ if (!globalObject) {
+ // We can't optimise at all :-(
+ emitOpcode(op_resolve_base);
+ instructions().append(dst->index());
+ instructions().append(addConstant(property));
+ return dst;
+ }
+
+ // Global object is the base
+ return emitLoad(dst, JSValue(globalObject));
}
RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
{
- emitOpcode(op_resolve_with_base);
- instructions().append(baseDst->index());
+ size_t depth = 0;
+ int index = 0;
+ JSObject* globalObject = 0;
+ if (!findScopedProperty(property, index, depth, false, globalObject) || !globalObject) {
+ // We can't optimise at all :-(
+ emitOpcode(op_resolve_with_base);
+ instructions().append(baseDst->index());
+ instructions().append(propDst->index());
+ instructions().append(addConstant(property));
+ return baseDst;
+ }
+
+ bool forceGlobalResolve = false;
+ if (m_regeneratingForExceptionInfo) {
+#if ENABLE(JIT)
+ forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size());
+#else
+ forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size());
+#endif
+ }
+
+ // Global object is the base
+ emitLoad(baseDst, JSValue(globalObject));
+
+ if (index != missingSymbolMarker() && !forceGlobalResolve) {
+ // Directly index the property lookup across multiple scopes.
+ emitGetScopedVar(propDst, depth, index, globalObject);
+ return baseDst;
+ }
+
+#if ENABLE(JIT)
+ m_codeBlock->addGlobalResolveInfo(instructions().size());
+#else
+ m_codeBlock->addGlobalResolveInstruction(instructions().size());
+#endif
+ emitOpcode(op_resolve_global);
instructions().append(propDst->index());
+ instructions().append(globalObject);
instructions().append(addConstant(property));
+ instructions().append(0);
+ instructions().append(0);
return baseDst;
}
-RegisterID* BytecodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
+void BytecodeGenerator::emitMethodCheck()
{
- emitOpcode(op_resolve_func);
- instructions().append(baseDst->index());
- instructions().append(funcDst->index());
- instructions().append(addConstant(property));
- return baseDst;
+ emitOpcode(op_method_check);
}
RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
{
#if ENABLE(JIT)
- m_codeBlock->addStructureStubInfo(StructureStubInfo(op_get_by_id));
+ m_codeBlock->addStructureStubInfo(StructureStubInfo(access_get_by_id));
#else
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
{
#if ENABLE(JIT)
- m_codeBlock->addStructureStubInfo(StructureStubInfo(op_put_by_id));
+ m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id));
#else
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
{
+ for (size_t i = m_forInContextStack.size(); i > 0; i--) {
+ ForInContext& context = m_forInContextStack[i - 1];
+ if (context.propertyRegister == property) {
+ emitOpcode(op_get_by_pname);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(property->index());
+ instructions().append(context.expectedSubscriptRegister->index());
+ instructions().append(context.iterRegister->index());
+ instructions().append(context.indexRegister->index());
+ return dst;
+ }
+ }
emitOpcode(op_get_by_val);
instructions().append(dst->index());
instructions().append(base->index());
return dst;
}
-RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
+RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
{
+ unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
+
emitOpcode(op_new_func);
instructions().append(dst->index());
- instructions().append(addConstant(n));
+ instructions().append(index);
return dst;
}
RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
{
+ FunctionBodyNode* function = n->body();
+ unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
+
emitOpcode(op_new_func_exp);
instructions().append(r0->index());
- instructions().append(addConstant(n));
+ instructions().append(index);
return r0;
}
return emitCall(op_call, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
}
+void BytecodeGenerator::createArgumentsIfNecessary()
+{
+ if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
+ emitOpcode(op_create_arguments);
+}
+
RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
{
+ createArgumentsIfNecessary();
return emitCall(op_call_eval, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
}
// Generate code for arguments.
Vector<RefPtr<RegisterID>, 16> argv;
argv.append(thisRegister);
- for (ArgumentListNode* n = argumentsNode->m_listNode.get(); n; n = n->m_next.get()) {
+ for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) {
argv.append(newTemporary());
// op_call requires the arguments to be a sequential range of registers
ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
return dst;
}
+RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* arguments)
+{
+ ASSERT(argCountDst->index() < arguments->index());
+ emitOpcode(op_load_varargs);
+ instructions().append(argCountDst->index());
+ instructions().append(arguments->index());
+ return argCountDst;
+}
+
+RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCountRegister, unsigned divot, unsigned startOffset, unsigned endOffset)
+{
+ ASSERT(func->refCount());
+ ASSERT(thisRegister->refCount());
+ ASSERT(dst != func);
+ if (m_shouldEmitProfileHooks) {
+ emitOpcode(op_profile_will_call);
+ instructions().append(func->index());
+
+#if ENABLE(JIT)
+ m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index());
+#endif
+ }
+
+ emitExpressionInfo(divot, startOffset, endOffset);
+
+ // Emit call.
+ emitOpcode(op_call_varargs);
+ instructions().append(dst->index()); // dst
+ instructions().append(func->index()); // func
+ instructions().append(argCountRegister->index()); // arg count
+ instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
+ if (m_shouldEmitProfileHooks) {
+ emitOpcode(op_profile_did_call);
+ instructions().append(func->index());
+ }
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
{
if (m_codeBlock->needsFullScopeChain()) {
// Generate code for arguments.
Vector<RefPtr<RegisterID>, 16> argv;
argv.append(newTemporary()); // reserve space for "this"
- for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode.get() : 0; n; n = n->m_next.get()) {
+ for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode : 0; n; n = n->m_next) {
argv.append(newTemporary());
// op_construct requires the arguments to be a sequential range of registers
ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
return dst;
}
+RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count)
+{
+ emitOpcode(op_strcat);
+ instructions().append(dst->index());
+ instructions().append(src->index());
+ instructions().append(count);
+
+ return dst;
+}
+
+void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src)
+{
+ emitOpcode(op_to_primitive);
+ instructions().append(dst->index());
+ instructions().append(src->index());
+}
+
RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope)
{
ASSERT(scope->isTemporary());
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
+ createArgumentsIfNecessary();
return emitUnaryNoDstOp(op_push_scope, scope);
}
LabelScope* BytecodeGenerator::breakTarget(const Identifier& name)
{
// Reclaim free label scopes.
- while (m_labelScopes.size() && !m_labelScopes.last().refCount())
+ //
+ // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()',
+ // however sometimes this appears to lead to GCC going a little haywire and entering the loop with
+ // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to
+ // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the
+ // loop condition is a workaround.
+ while (m_labelScopes.size()) {
+ if (m_labelScopes.last().refCount())
+ break;
m_labelScopes.removeLast();
+ }
if (!m_labelScopes.size())
return 0;
}
if (nNormalScopes) {
+ size_t begin = instructions().size();
+
// We need to remove a number of dynamic scopes to get to the next
// finally block
emitOpcode(op_jmp_scopes);
// If topScope == bottomScope then there isn't actually a finally block
// left to emit, so make the jmp_scopes jump directly to the target label
if (topScope == bottomScope) {
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
// Otherwise we just use jmp_scopes to pop a group of scopes and go
// to the next instruction
RefPtr<Label> nextInsn = newLabel();
- instructions().append(nextInsn->offsetFrom(instructions().size()));
+ instructions().append(nextInsn->bind(begin, instructions().size()));
emitLabel(nextInsn.get());
}
- // To get here there must be at least one finally block present
- do {
- ASSERT(topScope->isFinallyBlock);
+ while (topScope > bottomScope && topScope->isFinallyBlock) {
emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
--topScope;
- if (!topScope->isFinallyBlock)
- break;
- } while (topScope > bottomScope);
+ }
}
return emitJump(target);
}
if (m_finallyDepth)
return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
+ size_t begin = instructions().size();
+
emitOpcode(op_jmp_scopes);
instructions().append(scopeDelta);
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return target;
}
-RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target)
+RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
+{
+ size_t begin = instructions().size();
+
+ emitOpcode(op_get_pnames);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(i->index());
+ instructions().append(size->index());
+ instructions().append(breakTarget->bind(begin, instructions().size()));
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
{
+ size_t begin = instructions().size();
+
emitOpcode(op_next_pname);
instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(i->index());
+ instructions().append(size->index());
instructions().append(iter->index());
- instructions().append(target->offsetFrom(instructions().size()));
+ instructions().append(target->bind(begin, instructions().size()));
return dst;
}
RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end)
{
#if ENABLE(JIT)
- HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, 0 };
+ HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() };
#else
- HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth };
+ HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth };
#endif
m_codeBlock->addExceptionHandler(info);
return targetRegister;
}
-RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValuePtr message)
+RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue message)
{
emitOpcode(op_new_error);
instructions().append(dst->index());
instructions().append(static_cast<int>(type));
- instructions().append(addUnexpectedConstant(message));
+ instructions().append(addConstantValue(message)->index());
return dst;
}
PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally)
{
+ size_t begin = instructions().size();
+
emitOpcode(op_jsr);
instructions().append(retAddrDst->index());
- instructions().append(finally->offsetFrom(instructions().size()));
+ instructions().append(finally->bind(begin, instructions().size()));
+ emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it.
return finally;
}
instructions().append(retAddrSrc->index());
}
-void BytecodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
+void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value)
{
ControlFlowContext context;
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
+ createArgumentsIfNecessary();
+
emitOpcode(op_push_new_scope);
instructions().append(dst->index());
instructions().append(addConstant(property));
ASSERT(node->isNumber());
double value = static_cast<NumberNode*>(node)->value();
int32_t key = static_cast<int32_t>(value);
- ASSERT(JSValuePtr::makeInt32Fast(key) && (JSValuePtr::makeInt32Fast(key).getInt32Fast() == value));
ASSERT(key == value);
ASSERT(key >= min);
ASSERT(key <= max);
// We're emitting this after the clause labels should have been fixed, so
// the labels should not be "forward" references
ASSERT(!labels[i]->isForward());
- jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
+ jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
}
}
// We're emitting this after the clause labels should have been fixed, so
// the labels should not be "forward" references
ASSERT(!labels[i]->isForward());
- jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
+ jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
}
}
ASSERT(nodes[i]->isString());
UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep();
OffsetLocation location;
- location.branchOffset = labels[i]->offsetFrom(switchAddress);
-#if ENABLE(JIT)
- location.ctiOffset = 0;
-#endif
+ location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3);
jumpTable.offsetTable.add(clause, location);
}
}
m_switchContextStack.removeLast();
if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables();
- instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3);
+ instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable();
- prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes, min, max);
+ prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
} else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables();
- instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3);
+ instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable();
- prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes, min, max);
+ prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
} else {
ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables();
- instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3);
+ instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable();
- prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes);
+ prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes);
}
}