+2008-10-01 Cameron Zwarich <zwarich@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 21123: using "arguments" in a function should not force creation of an activation object
+ <https://bugs.webkit.org/show_bug.cgi?id=21123>
+
+ Make the 'arguments' object not require a JSActivation. We store the
+ 'arguments' object in the OptionalCalleeArguments call frame slot. We
+ need to be able to get the original 'arguments' object to tear it off
+ when returning from a function, but 'arguments' may be assigned to in a
+ number of ways.
+
+ Therefore, we use the OptionalCalleeArguments slot when we want to get
+ the original activation or we know that 'arguments' was not assigned a
+ different value. When 'arguments' may have been assigned a new value,
+ we use a new local variable that is initialized with 'arguments'. Since
+ a function parameter named 'arguments' may overwrite the value of
+ 'arguments', we also need to be careful to look up 'arguments' in the
+ symbol table, so we get the parameter named 'arguments' instead of the
+ local variable that we have added for holding the 'arguments' object.
+
+ This is a 19.1% win on the V8 Raytrace benchmark using the SunSpider
+ harness, and a 20.7% win using the V8 harness. This amounts to a 6.5%
+ total speedup on the V8 benchmark suite using the V8 harness.
+
+ * VM/CTI.cpp:
+ (JSC::CTI::privateCompileMainPass):
+ * VM/CodeBlock.h:
+ * VM/CodeGenerator.cpp:
+ (JSC::CodeGenerator::CodeGenerator):
+ * VM/Machine.cpp:
+ (JSC::Machine::unwindCallFrame):
+ (JSC::Machine::privateExecute):
+ (JSC::Machine::retrieveArguments):
+ (JSC::Machine::cti_op_init_arguments):
+ (JSC::Machine::cti_op_ret_activation_arguments):
+ * VM/Machine.h:
+ * VM/RegisterFile.h:
+ (JSC::RegisterFile::):
+ * kjs/Arguments.cpp:
+ (JSC::Arguments::mark):
+ (JSC::Arguments::fillArgList):
+ (JSC::Arguments::getOwnPropertySlot):
+ (JSC::Arguments::put):
+ * kjs/Arguments.h:
+ (JSC::Arguments::setRegisters):
+ (JSC::Arguments::init):
+ (JSC::Arguments::Arguments):
+ (JSC::Arguments::copyRegisters):
+ (JSC::JSActivation::copyRegisters):
+ * kjs/JSActivation.cpp:
+ (JSC::JSActivation::argumentsGetter):
+ * kjs/JSActivation.h:
+ (JSC::JSActivation::JSActivationData::JSActivationData):
+ * kjs/grammar.y:
+ * kjs/nodes.h:
+ (JSC::ScopeNode::setUsesArguments):
+ * masm/X86Assembler.h:
+ (JSC::X86Assembler::):
+ (JSC::X86Assembler::orl_mr):
+
2008-10-01 Kevin McCullough <kmccullough@apple.com>
Rubberstamped by Geoff .
break;
}
case op_ret: {
- // Check for an activation - if there is one, jump to the hook below.
- m_jit.cmpl_i32m(0, RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi);
+ // If there is an activation or an 'arguments' object, we tear it
+ // off by jumping to the hook below.
+ m_jit.movl_mr(RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
+ m_jit.orl_mr(RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
+ m_jit.cmpl_i32r(0, X86::eax);
X86Assembler::JmpSrc activation = m_jit.emitUnlinkedJne();
X86Assembler::JmpDst activated = m_jit.label();
m_jit.pushl_r(X86::edx);
m_jit.ret();
- // Activation hook
+ // Activation and 'arguments' hook
m_jit.link(activation, m_jit.label());
- emitCall(i, Machine::cti_op_ret_activation);
+ emitCall(i, Machine::cti_op_ret_activation_arguments);
m_jit.link(m_jit.emitUnlinkedJmp(), activated);
// Profiling hook
int thisRegister;
bool needsFullScopeChain;
bool usesEval;
+ bool usesArguments;
CodeType codeType;
RefPtr<SourceProvider> source;
unsigned sourceOffset;
emitOpcode(op_init);
codeBlock->globalData = m_globalData;
- if (functionBody->usesArguments()) {
+ bool usesArguments = functionBody->usesArguments();
+ codeBlock->usesArguments = usesArguments;
+ if (usesArguments) {
emitOpcode(op_init_arguments);
- m_codeBlock->needsFullScopeChain = true;
m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);
- symbolTable->add(propertyNames().arguments.ustring().rep(), SymbolTableEntry(RegisterFile::OptionalCalleeArguments));
+ addVar(propertyNames().arguments, false);
}
const Node::FunctionStack& functionStack = functionBody->functionStack();
if (oldCodeBlock->needsFullScopeChain)
scopeChain->deref();
- // If this call frame created an activation, tear it off.
- if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+ // If this call frame created an activation or an 'arguments' object, tear it off.
+ if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
ASSERT(activation->isObject(&JSActivation::info));
- activation->copyRegisters();
+ activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+ } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
+ ASSERT(arguments->isObject(&Arguments::info));
+ arguments->copyRegisters();
}
void* returnPC = r[RegisterFile::ReturnPC].v();
int result = (++vPC)->u.operand;
- if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+ // If this call frame created an activation or an 'arguments' object, tear it off.
+ if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
ASSERT(activation->isObject(&JSActivation::info));
- activation->copyRegisters();
+ activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+ } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
+ ASSERT(arguments->isObject(&Arguments::info));
+ arguments->copyRegisters();
}
if (*enabledProfilerReference)
NEXT_OPCODE;
}
BEGIN_OPCODE(op_init_arguments) {
- JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
- r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
+ JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
+ Arguments* arguments;
+ if (activation) {
+ ASSERT(activation->isObject(&JSActivation::info));
+ arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
+ } else
+ arguments = new (exec) Arguments(exec, r);
+ r[RegisterFile::OptionalCalleeArguments] = arguments;
+ r[RegisterFile::ArgumentsRegister] = arguments;
+
++vPC;
NEXT_OPCODE;
}
if (!r)
return jsNull();
- Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].jsValue(exec));
- if (!arguments) {
- JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
- if (!activation) {
- activation = new (exec) JSActivation(exec, function->m_body, r);
- r[RegisterFile::OptionalCalleeActivation] = activation;
+ JSValue* arguments;
+ CodeBlock* codeBlock = Machine::codeBlock(r);
+ if (codeBlock->usesArguments) {
+ ASSERT(codeBlock->codeType == FunctionCode);
+ SymbolTable& symbolTable = static_cast<FunctionBodyNode*>(codeBlock->ownerNode)->symbolTable();
+ int argumentsIndex = symbolTable.get(exec->propertyNames().arguments.ustring().rep()).getIndex();
+ arguments = r[argumentsIndex].jsValue(exec);
+ } else {
+ arguments = r[RegisterFile::OptionalCalleeArguments].getJSValue();
+ if (!arguments) {
+ JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
+ if (activation)
+ arguments = new (exec) Arguments(exec, activation);
+ else
+ arguments = new (exec) Arguments(exec, r);
+ r[RegisterFile::OptionalCalleeArguments] = arguments;
}
-
- arguments = activation->createArgumentsObject(exec);
- r[RegisterFile::OptionalCalleeArguments] = arguments;
+ ASSERT(arguments->isObject(&Arguments::info));
}
return arguments;
{
ExecState* exec = ARG_exec;
Register* r = ARG_r;
- JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
- r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
+
+ JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
+ Arguments* arguments;
+ if (activation) {
+ ASSERT(activation->isObject(&JSActivation::info));
+ arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
+ } else
+ arguments = new (exec) Arguments(exec, r);
+ r[RegisterFile::OptionalCalleeArguments] = arguments;
+ r[RegisterFile::ArgumentsRegister] = arguments;
}
-void Machine::cti_op_ret_activation(CTI_ARGS)
+void Machine::cti_op_ret_activation_arguments(CTI_ARGS)
{
- ExecState* exec = ARG_exec;
Register* r = ARG_r;
- JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec));
- ASSERT(activation);
-
- ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
- ASSERT(activation->isObject(&JSActivation::info));
- activation->copyRegisters();
+ // If this call frame created an activation or an 'arguments' object, tear it off.
+ if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
+ ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
+ ASSERT(activation->isObject(&JSActivation::info));
+ activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+ } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
+ ASSERT(arguments->isObject(&Arguments::info));
+ arguments->copyRegisters();
+ }
}
void Machine::cti_op_ret_profiler(CTI_ARGS)
static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
static void SFX_CALL cti_op_init_arguments(CTI_ARGS);
- static void SFX_CALL cti_op_ret_activation(CTI_ARGS);
+ static void SFX_CALL cti_op_ret_activation_arguments(CTI_ARGS);
static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
};
enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
+ enum { ArgumentsRegister = 0 };
enum { DefaultCapacity = 2 * 1024 * 1024 / sizeof(Register) };
enum { DefaultMaxGlobals = 8 * 1024 };
const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
-struct ArgumentsData : Noncopyable {
- ArgumentsData(JSActivation* activation, unsigned numParameters, int firstParameterIndex, unsigned numArguments, JSFunction* callee)
- : activation(activation)
- , numParameters(numParameters)
- , firstParameterIndex(firstParameterIndex)
- , numArguments(numArguments)
- , extraArguments(0)
- , callee(callee)
- , overrodeLength(false)
- , overrodeCallee(false)
- {
- }
-
- JSActivation* activation;
-
- unsigned numParameters;
- int firstParameterIndex;
- unsigned numArguments;
- Register* extraArguments;
- OwnArrayPtr<bool> deletedArguments;
- Register extraArgumentsFixedBuffer[4];
-
- JSFunction* callee;
- bool overrodeLength : 1;
- bool overrodeCallee : 1;
-};
-
-// ECMA 10.1.8
-Arguments::Arguments(ExecState* exec, JSFunction* function, JSActivation* activation, int firstParameterIndex, Register* argv, int argc)
- : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
- , d(new ArgumentsData(activation, function->numParameters(), firstParameterIndex, argc, function))
-{
- ASSERT(activation);
-
- if (d->numArguments > d->numParameters) {
- unsigned numExtraArguments = d->numArguments - d->numParameters;
- Register* extraArguments;
- if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
- extraArguments = new Register[numExtraArguments];
- else
- extraArguments = d->extraArgumentsFixedBuffer;
- for (unsigned i = 0; i < numExtraArguments; ++i)
- extraArguments[i] = argv[d->numParameters + i];
- d->extraArguments = extraArguments;
- }
-}
-
Arguments::~Arguments()
{
if (d->extraArguments != d->extraArgumentsFixedBuffer)
{
JSObject::mark();
+ for (unsigned i = 0; i < d->numParameters; ++i) {
+ if (!d->registers[i].marked())
+ d->registers[i].mark();
+ }
+
if (d->extraArguments) {
unsigned numExtraArguments = d->numArguments - d->numParameters;
for (unsigned i = 0; i < numExtraArguments; ++i) {
if (!d->callee->marked())
d->callee->mark();
- if (!d->activation->marked())
+ if (d->activation && !d->activation->marked())
d->activation->mark();
}
}
if (d->numParameters == d->numArguments) {
- args.initialize(&d->activation->registerAt(d->firstParameterIndex), d->numArguments);
+ args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
return;
}
unsigned parametersLength = min(d->numParameters, d->numArguments);
unsigned i = 0;
for (; i < parametersLength; ++i)
- args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
+ args.append(d->registers[d->firstParameterIndex + i].jsValue(exec));
for (; i < d->numArguments; ++i)
- args.append(d->extraArguments[i - d->numParameters].getJSValue());
+ args.append(d->extraArguments[i - d->numParameters].jsValue(exec));
return;
}
unsigned i = 0;
for (; i < parametersLength; ++i) {
if (!d->deletedArguments[i])
- args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
+ args.append(d->registers[d->firstParameterIndex + i].jsValue(exec));
else
args.append(get(exec, i));
}
for (; i < d->numArguments; ++i) {
if (!d->deletedArguments[i])
- args.append(d->extraArguments[i - d->numParameters].getJSValue());
+ args.append(d->extraArguments[i - d->numParameters].jsValue(exec));
else
args.append(get(exec, i));
}
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
+ slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
else
- slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
+ slot.setValue(d->extraArguments[i - d->numParameters].jsValue(exec));
return true;
}
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
+ slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
else
- slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
+ slot.setValue(d->extraArguments[i - d->numParameters].jsValue(exec));
return true;
}
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
+ d->registers[d->firstParameterIndex + i] = value;
else
d->extraArguments[i - d->numParameters] = value;
return;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
+ d->registers[d->firstParameterIndex + i] = value;
else
d->extraArguments[i - d->numParameters] = value;
return;
#ifndef Arguments_h
#define Arguments_h
-#include "JSObject.h"
+#include "JSActivation.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "Machine.h"
namespace JSC {
- class JSActivation;
- class JSFunction;
- class Register;
+ struct ArgumentsData : Noncopyable {
+ JSActivation* activation;
+
+ unsigned numParameters;
+ int firstParameterIndex;
+ unsigned numArguments;
+
+ Register* registers;
+ OwnArrayPtr<Register> registerArray;
+
+ Register* extraArguments;
+ OwnArrayPtr<bool> deletedArguments;
+ Register extraArgumentsFixedBuffer[4];
+
+ JSFunction* callee;
+ bool overrodeLength : 1;
+ bool overrodeCallee : 1;
+ };
- struct ArgumentsData;
class Arguments : public JSObject {
public:
- Arguments(ExecState*, JSFunction*, JSActivation*, int firstArgumentIndex, Register* argv, int argc);
+ Arguments(ExecState*, Register* callFrame);
+ Arguments(ExecState*, JSActivation*);
virtual ~Arguments();
static const ClassInfo info;
void fillArgList(ExecState*, ArgList&);
+ void copyRegisters();
+ void setRegisters(Register* registers) { d->registers = registers; }
+
private:
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual const ClassInfo* classInfo() const { return &info; }
+ void init(ExecState*, Register* callFrame);
+
OwnPtr<ArgumentsData> d;
};
+ inline void Arguments::init(ExecState* exec, Register* callFrame)
+ {
+ JSFunction* callee;
+ int firstParameterIndex;
+ Register* argv;
+ int numArguments;
+ exec->machine()->getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
+
+ d->numParameters = callee->numParameters();
+ d->firstParameterIndex = firstParameterIndex;
+ d->numArguments = numArguments;
+
+ d->registers = callFrame;
+
+ Register* extraArguments;
+ if (d->numArguments <= d->numParameters)
+ extraArguments = 0;
+ else {
+ unsigned numExtraArguments = d->numArguments - d->numParameters;
+ if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
+ extraArguments = new Register[numExtraArguments];
+ else
+ extraArguments = d->extraArgumentsFixedBuffer;
+ for (unsigned i = 0; i < numExtraArguments; ++i)
+ extraArguments[i] = argv[d->numParameters + i];
+ }
+
+ d->extraArguments = extraArguments;
+
+ d->callee = callee;
+ d->overrodeLength = false;
+ d->overrodeCallee = false;
+ }
+
+ inline Arguments::Arguments(ExecState* exec, Register* callFrame)
+ : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
+ , d(new ArgumentsData)
+ {
+ d->activation = 0;
+ init(exec, callFrame);
+ }
+
+ inline Arguments::Arguments(ExecState* exec, JSActivation* activation)
+ : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
+ , d(new ArgumentsData)
+ {
+ ASSERT(activation);
+ d->activation = activation;
+ init(exec, &activation->registerAt(0));
+ }
+
+ inline void Arguments::copyRegisters()
+ {
+ ASSERT(!d->activation);
+ ASSERT(!d->registerArray);
+
+ size_t numParametersMinusThis = d->callee->m_body->generatedByteCode().numParameters - 1;
+
+ if (!numParametersMinusThis)
+ return;
+
+ int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+ size_t registerArraySize = numParametersMinusThis;
+
+ Register* registerArray = new Register[registerArraySize];
+ memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
+ d->registerArray.set(registerArray);
+ d->registers = registerArray + registerOffset;
+ }
+
+ // This JSActivation function is defined here so it can get at Arguments::setRegisters.
+ inline void JSActivation::copyRegisters(JSValue* arguments)
+ {
+ ASSERT(!d()->registerArray);
+
+ size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
+ size_t numVars = d()->functionBody->generatedByteCode().numVars;
+ size_t numLocals = numVars + numParametersMinusThis;
+
+ if (!numLocals)
+ return;
+
+ int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+ size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
+
+ Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
+ setRegisters(registerArray + registerOffset, registerArray);
+ if (arguments) {
+ ASSERT(arguments->isObject(&Arguments::info));
+ static_cast<Arguments*>(arguments)->setRegisters(registerArray + registerOffset);
+ }
+ }
+
} // namespace JSC
#endif // Arguments_h
{
JSActivation* thisObj = static_cast<JSActivation*>(slot.slotBase());
- Arguments* arguments = static_cast<Arguments*>(thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].jsValue(exec));
- if (!arguments) {
- arguments = thisObj->createArgumentsObject(exec);
- thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
+ JSValue* arguments;
+ if (thisObj->d()->functionBody->usesArguments()) {
+ PropertySlot slot;
+ thisObj->symbolTableGet(exec->propertyNames().arguments, slot);
+ arguments = slot.getValue(exec, exec->propertyNames().arguments);
+ } else {
+ arguments = thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].getJSValue();
+ if (!arguments) {
+ arguments = new (exec) Arguments(exec, thisObj);
+ thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
+ }
+ ASSERT(arguments->isObject(&Arguments::info));
}
return arguments;
return argumentsGetter;
}
-Arguments* JSActivation::createArgumentsObject(ExecState* exec)
-{
- JSFunction* function;
- Register* argv;
- int argc;
- int firstParameterIndex;
- exec->machine()->getArgumentsData(d()->registers, function, firstParameterIndex, argv, argc);
-
- return new (exec) Arguments(exec, function, this, firstParameterIndex, argv, argc);
-}
-
} // namespace JSC
class JSActivation : public JSVariableObject {
typedef JSVariableObject Base;
public:
- JSActivation(ExecState* exec, PassRefPtr<FunctionBodyNode>, Register*);
+ JSActivation(ExecState*, PassRefPtr<FunctionBodyNode>, Register*);
virtual ~JSActivation();
-
+
virtual void mark();
virtual bool isDynamicScope() const;
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
- inline void uncheckedSymbolTableGet(int index, PropertySlot& slot)
- {
- slot.setRegisterSlot(®isterAt(index));
- }
-
- inline JSValue* uncheckedSymbolTableGetValue(int index)
- {
- return registerAt(index).getJSValue();
- }
-
virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
- inline void uncheckedSymbolTablePut(int index, JSValue* value)
- {
- registerAt(index) = value;
- }
-
virtual void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual JSObject* toThisObject(ExecState*) const;
- void copyRegisters();
+ void copyRegisters(JSValue* arguments);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
- NEVER_INLINE Arguments* createArgumentsObject(ExecState*);
-
private:
struct JSActivationData : public JSVariableObjectData {
- JSActivationData(PassRefPtr<FunctionBodyNode> functionBody_, Register* registers)
- : JSVariableObjectData(&functionBody_->symbolTable(), registers)
- , functionBody(functionBody_)
+ JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers)
+ : JSVariableObjectData(&functionBody->symbolTable(), registers)
+ , functionBody(functionBody)
{
}
- RefPtr<FunctionBodyNode> functionBody; // Owns the symbol table and code block
+ RefPtr<FunctionBodyNode> functionBody;
};
static JSValue* argumentsGetter(ExecState*, const Identifier&, const PropertySlot&);
JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); }
};
- inline void JSActivation::copyRegisters()
- {
- ASSERT(!d()->registerArray);
-
- size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
- size_t numVars = d()->functionBody->generatedByteCode().numVars;
- size_t numLocals = numVars + numParametersMinusThis;
-
- if (!numLocals)
- return;
-
- int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
- size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
-
- Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
- setRegisters(registerArray + registerOffset, registerArray);
- }
-
} // namespace JSC
#endif // JSActivation_h
| NUMBER ':' AssignmentExpr { $$ = createNodeFeatureInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, Identifier(GLOBAL_DATA, UString::from($1)), $3.m_node, PropertyNode::Constant), $3.m_featureInfo, $3.m_numConstants); }
| IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, 0, $6, LEXER->sourceRange($5, $7)), ClosureFeature, 0); DBG($6, @5, @7); if (!$$.m_node) YYABORT; }
| IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceRange($6, $8)), $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); if (!$$.m_node) YYABORT; }
+ { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceRange($6, $8)), $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); if (!$$.m_node) YYABORT; }
;
PropertyList:
FunctionDeclaration:
FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceRange($5, $7)), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); }
| FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); }
+ { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); }
;
FunctionExpr:
FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, LEXER->sourceRange($4, $6)), ClosureFeature, 0); DBG($5, @4, @6); }
- | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceRange($5, $7), $3.m_node.head), $3.m_featureInfo | ClosureFeature, 0); DBG($6, @5, @7); }
+ | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceRange($5, $7), $3.m_node.head), $3.m_featureInfo | ClosureFeature, 0); $6->setUsesArguments($6->usesArguments() | ($3.m_featureInfo & ArgumentsFeature)); DBG($6, @5, @7); }
| FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $6, LEXER->sourceRange($5, $7)), ClosureFeature, 0); DBG($6, @5, @7); }
- | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); }
+ | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); }
;
FormalParameterList:
bool usesEval() const { return m_usesEval; }
bool needsClosure() const { return m_needsClosure; }
bool usesArguments() const { return m_usesArguments; }
+ void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; }
VarStack& varStack() { return m_varStack; }
FunctionStack& functionStack() { return m_functionStack; }
OP_ADD_EvGv = 0x01,
OP_ADD_GvEv = 0x03,
OP_OR_EvGv = 0x09,
+ OP_OR_GvEv = 0x0B,
OP_2BYTE_ESCAPE = 0x0F,
OP_AND_EvGv = 0x21,
OP_SUB_EvGv = 0x29,
emitModRm_rr(src, dst);
}
+ void orl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ m_buffer->putByte(OP_OR_GvEv);
+ emitModRm_rm(dst, base, offset);
+ }
+
void orl_i32r(int imm, RegisterID dst)
{
m_buffer->putByte(OP_GROUP1_EvIb);
+2008-10-01 Cameron Zwarich <zwarich@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add some tests for the 'arguments' object. The included failures are
+ intentional. They are for regressions introduced in r37050, and they
+ will hopefully be fixed in the near future.
+
+ * fast/js/arguments-expected.txt:
+ * fast/js/function-dot-arguments-expected.txt:
+ * fast/js/resources/arguments.js:
+ * fast/js/resources/function-dot-arguments.js:
+
2008-10-01 Kevin McCullough <kmccullough@apple.com>
Reviewed by Dan Bernstein.
PASS access_after_delete_extra_3(1, 2, 3, 4, 5) is 3
PASS access_after_delete_extra_5(1, 2, 3, 4, 5) is 5
PASS argumentsParam(true) is true
+FAIL argumentsVarUndefined() should be undefined. Was [object Arguments]
+FAIL argumentsConstUndefined() should be undefined. Was [object Arguments]
PASS successfullyParsed is true
TEST COMPLETE
PASS assignTest() is true
+FAIL assignVarUndefinedTest() should be undefined. Was [object Arguments]
+FAIL assignVarUndefinedTest2() should be undefined. Was [object Arguments]
PASS assignVarInitTest() is true
PASS assignVarInitTest2() is true
+FAIL assignConstUndefinedTest() should be undefined. Was [object Arguments]
+FAIL assignConstUndefinedTest2() should be undefined. Was [object Arguments]
PASS assignConstInitTest() is true
PASS assignConstInitTest2() is true
PASS assignForInitTest() is true
PASS assignForInitTest2() is true
PASS assignForInInitTest() is true
-FAIL paramInitTest(true) should be true (of type boolean). Was [object Arguments] (of type object).
+PASS paramInitTest(true) is true
+PASS tearOffTest()[0] is true
+PASS tearOffTest2(true)[0] is true
PASS successfullyParsed is true
TEST COMPLETE
{
return arguments;
}
-
shouldBeTrue("argumentsParam(true)");
+function argumentsVarUndefined()
+{
+ var arguments;
+ return arguments;
+}
+shouldBeUndefined("argumentsVarUndefined()");
+
+function argumentsConstUndefined()
+{
+ const arguments;
+ return arguments;
+}
+shouldBeUndefined("argumentsConstUndefined()");
+
var successfullyParsed = true;
arguments = true;
return g();
}
-
shouldBeTrue("assignTest()");
+function assignVarUndefinedTest()
+{
+ function g()
+ {
+ return assignVarUndefinedTest.arguments;
+ }
+
+ var arguments;
+ return g();
+}
+shouldBeUndefined("assignVarUndefinedTest()");
+
+function assignVarUndefinedTest2()
+{
+ function g()
+ {
+ return assignVarUndefinedTest2.arguments;
+ }
+
+ var a, arguments;
+ return g();
+}
+shouldBeUndefined("assignVarUndefinedTest2()");
+
function assignVarInitTest()
{
function g()
var arguments = true;
return g();
}
-
shouldBeTrue("assignVarInitTest()");
function assignVarInitTest2()
var a, arguments = true;
return g();
}
-
shouldBeTrue("assignVarInitTest2()");
+function assignConstUndefinedTest()
+{
+ function g()
+ {
+ return assignConstUndefinedTest.arguments;
+ }
+
+ var arguments;
+ return g();
+}
+shouldBeUndefined("assignConstUndefinedTest()");
+
+function assignConstUndefinedTest2()
+{
+ function g()
+ {
+ return assignConstUndefinedTest2.arguments;
+ }
+
+ var a, arguments;
+ return g();
+}
+shouldBeUndefined("assignConstUndefinedTest2()");
+
function assignConstInitTest()
{
function g()
const arguments = true;
return g();
}
-
shouldBeTrue("assignConstInitTest()");
function assignConstInitTest2()
const a, arguments = true;
return g();
}
-
shouldBeTrue("assignConstInitTest2()");
function assignForInitTest()
for (var arguments = true; false;) { }
return g();
}
-
shouldBeTrue("assignForInitTest()");
function assignForInitTest2()
for (var a, arguments = true; false;) { }
return g();
}
-
shouldBeTrue("assignForInitTest2()");
function assignForInInitTest()
for (arguments = true; false;) { }
return g();
}
-
shouldBeTrue("assignForInInitTest()");
function paramInitTest(arguments)
return g();
}
-
shouldBeTrue("paramInitTest(true)");
+function tearOffTest()
+{
+ function g()
+ {
+ var a = 1;
+ return arguments;
+ }
+
+ var b = 2;
+ var arguments = g(true);
+ return arguments;
+}
+shouldBeTrue("tearOffTest()[0]");
+
+function tearOffTest2()
+{
+ function g(a)
+ {
+ var arguments = a;
+ var b = 2;
+ return arguments;
+ }
+
+ var c = 3;
+ return g(arguments);
+}
+shouldBeTrue("tearOffTest2(true)[0]");
+
var successfullyParsed = true;