Commit fdaf8dcc authored by barraclough@apple.com's avatar barraclough@apple.com

Bug 39399 - Move responsibility for verifying constructors return objects from...

Bug 39399 - Move responsibility for verifying constructors return objects from the caller to the callee.
        
Reviewed by Geoff Garen.

This is a necessary step to move object creation from caller to callee.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
* bytecode/Opcode.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitReturn):
(JSC::BytecodeGenerator::emitConstruct):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::isConstructor):
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionBodyNode::emitBytecode):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITCall.cpp:
(JSC::JIT::emit_op_constructor_ret):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_constructor_ret):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@59817 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f8790ba9
2010-05-19 Gavin Barraclough <barraclough@apple.com>
Reviewed by Geoff Garen.
Bug 39399 - Move responsibility for verifying constructors return objects from the caller to the callee.
This is a necessary step to move object creation from caller to callee.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
* bytecode/Opcode.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitReturn):
(JSC::BytecodeGenerator::emitConstruct):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::isConstructor):
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionBodyNode::emitBytecode):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITCall.cpp:
(JSC::JIT::emit_op_constructor_ret):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_constructor_ret):
2010-05-19 Gavin Barraclough <barraclough@apple.com>
Reviewed by NOBODY (build fix).
......
......@@ -1071,6 +1071,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data());
break;
}
case op_constructor_ret: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
printf("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
break;
}
case op_construct: {
int dst = (++it)->u.operand;
int func = (++it)->u.operand;
......@@ -1081,12 +1087,6 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(exec, dst).data(), registerName(exec, func).data(), argCount, registerOffset, registerName(exec, proto).data(), registerName(exec, thisRegister).data());
break;
}
case op_construct_verify: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
printf("[%4d] construct_verify\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
break;
}
case op_strcat: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
......
......@@ -160,10 +160,10 @@ namespace JSC {
macro(op_tear_off_activation, 3) \
macro(op_tear_off_arguments, 2) \
macro(op_ret, 2) \
macro(op_constructor_ret, 3) \
macro(op_method_check, 1) \
\
macro(op_construct, 7) \
macro(op_construct_verify, 3) \
macro(op_strcat, 4) \
macro(op_to_primitive, 3) \
\
......
......@@ -365,7 +365,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
++m_nextParameterIndex;
++m_codeBlock->m_numParameters;
if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
if (!isConstructor() && (functionBody->usesThis() || m_shouldEmitDebugHooks)) {
emitOpcode(op_convert_this);
instructions().append(m_thisRegister.index());
}
......@@ -1541,6 +1541,15 @@ RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
instructions().append(m_codeBlock->argumentsRegister());
}
// Constructors use op_constructor_ret to check the result is an
// object, unless we can trivially determine the check is not
// necessary (currently, if the return value is 'this').
if (isConstructor() && (src->index() != m_thisRegister.index())) {
emitOpcode(op_constructor_ret);
instructions().append(src->index());
instructions().append(m_thisRegister.index());
return src;
}
return emitUnaryNoDstOp(op_ret, src);
}
......@@ -1607,10 +1616,6 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
instructions().append(funcProto->index()); // proto
instructions().append(argv[0]->index()); // thisRegister
emitOpcode(op_construct_verify);
instructions().append(dst->index());
instructions().append(argv[0]->index());
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
instructions().append(func->index());
......
......@@ -83,6 +83,8 @@ namespace JSC {
JSGlobalData* globalData() const { return m_globalData; }
const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; }
bool isConstructor() { return m_codeBlock->m_isConstructor; }
void generate();
// Returns the register corresponding to a local variable, or 0 if no
......
......@@ -1979,7 +1979,7 @@ RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, Registe
return 0;
}
RegisterID* r0 = generator.emitLoad(0, jsUndefined());
RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
generator.emitReturn(r0);
return 0;
......
......@@ -3840,6 +3840,37 @@ skip_id_custom_self:
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_constructor_ret) {
/* ret result(r)
Return register result as the return value of the current
function call, writing it into the caller's expected return
value register. In addition, unwind one call frame and
restore the scope chain, code block instruction pointer and
register base to those of the calling function.
*/
int result = vPC[1].u.operand;
if (callFrame->codeBlock()->needsFullScopeChain())
callFrame->scopeChain()->deref();
JSValue returnValue = callFrame->r(result).jsValue();
if (UNLIKELY(!returnValue.isObject()))
returnValue = callFrame->r(vPC[2].u.operand).jsValue();
vPC = callFrame->returnPC();
int dst = callFrame->returnValueRegister();
callFrame = callFrame->callerFrame();
if (callFrame->hasHostCallFrameFlag())
return returnValue;
callFrame->r(dst) = returnValue;
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_enter) {
/* enter
......@@ -4017,25 +4048,6 @@ skip_id_custom_self:
exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
goto vm_throw;
}
DEFINE_OPCODE(op_construct_verify) {
/* construct_verify dst(r) override(r)
Verifies that register dst holds an object. If not, moves
the object in register override to register dst.
*/
int dst = vPC[1].u.operand;
if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
vPC += OPCODE_LENGTH(op_construct_verify);
NEXT_INSTRUCTION();
}
int override = vPC[2].u.operand;
callFrame->r(dst) = callFrame->r(override);
vPC += OPCODE_LENGTH(op_construct_verify);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_strcat) {
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
......
......@@ -221,7 +221,6 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_call_varargs)
DEFINE_OP(op_catch)
DEFINE_OP(op_construct)
DEFINE_OP(op_construct_verify)
DEFINE_OP(op_convert_this)
DEFINE_OP(op_init_arguments)
DEFINE_OP(op_create_arguments)
......@@ -302,6 +301,7 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_resolve_skip)
DEFINE_OP(op_resolve_with_base)
DEFINE_OP(op_ret)
DEFINE_OP(op_constructor_ret)
DEFINE_OP(op_rshift)
DEFINE_OP(op_urshift)
DEFINE_OP(op_sret)
......@@ -389,7 +389,6 @@ void JIT::privateCompileSlowCases()
DEFINE_SLOWCASE_OP(op_call_eval)
DEFINE_SLOWCASE_OP(op_call_varargs)
DEFINE_SLOWCASE_OP(op_construct)
DEFINE_SLOWCASE_OP(op_construct_verify)
DEFINE_SLOWCASE_OP(op_convert_this)
#if !USE(JSVALUE32)
DEFINE_SLOWCASE_OP(op_div)
......
......@@ -653,7 +653,6 @@ namespace JSC {
void emit_op_call_varargs(Instruction*);
void emit_op_catch(Instruction*);
void emit_op_construct(Instruction*);
void emit_op_construct_verify(Instruction*);
void emit_op_convert_this(Instruction*);
void emit_op_create_arguments(Instruction*);
void emit_op_debug(Instruction*);
......@@ -730,6 +729,7 @@ namespace JSC {
void emit_op_resolve_skip(Instruction*);
void emit_op_resolve_with_base(Instruction*);
void emit_op_ret(Instruction*);
void emit_op_constructor_ret(Instruction*);
void emit_op_rshift(Instruction*);
void emit_op_sret(Instruction*);
void emit_op_strcat(Instruction*);
......@@ -758,7 +758,6 @@ namespace JSC {
void emitSlow_op_call_eval(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_construct_verify(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
......
......@@ -151,25 +151,35 @@ void JIT::emit_op_ret(Instruction* currentInstruction)
ret();
}
void JIT::emit_op_construct_verify(Instruction* currentInstruction)
void JIT::emit_op_constructor_ret(Instruction* currentInstruction)
{
unsigned dst = currentInstruction[1].u.operand;
unsigned result = currentInstruction[1].u.operand;
unsigned thisReg = currentInstruction[2].u.operand;
emitLoad(dst, regT1, regT0);
addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
// We could JIT generate the deref, only calling out to C when the refcount hits zero.
if (m_codeBlock->needsFullScopeChain())
JITStubCall(this, cti_op_ret_scopeChain).call();
emitLoad(result, regT1, regT0);
Jump notJSCell = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
addSlowCase(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType)));
}
Jump notObject = branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType));
void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
unsigned src = currentInstruction[2].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
linkSlowCase(iter);
linkSlowCase(iter);
emitLoad(src, regT1, regT0);
emitStore(dst, regT1, regT0);
restoreReturnAddressBeforeReturn(regT2);
ret();
notJSCell.link(this);
notObject.link(this);
emitLoad(thisReg, regT1, regT0);
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
restoreReturnAddressBeforeReturn(regT2);
ret();
}
void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
......
......@@ -789,6 +789,48 @@ void JIT::emit_op_ret(Instruction* currentInstruction)
ret();
}
void JIT::emit_op_constructor_ret(Instruction* currentInstruction)
{
// We could JIT generate the deref, only calling out to C when the refcount hits zero.
if (m_codeBlock->needsFullScopeChain())
JITStubCall(this, cti_op_ret_scopeChain).call();
ASSERT(callFrameRegister != regT1);
ASSERT(regT1 != returnValueRegister);
ASSERT(returnValueRegister != callFrameRegister);
// Return the result in %eax.
emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister);
Jump notJSCell = emitJumpIfNotJSCell(returnValueRegister);
loadPtr(Address(returnValueRegister, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
Jump notObject = branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType));
// Grab the return address.
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
// Restore our caller's "r".
emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
// Return.
restoreReturnAddressBeforeReturn(regT1);
ret();
// Return 'this' in %eax.
notJSCell.link(this);
notObject.link(this);
emitGetVirtualRegister(currentInstruction[2].u.operand, returnValueRegister);
// Grab the return address.
emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
// Restore our caller's "r".
emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
// Return.
restoreReturnAddressBeforeReturn(regT1);
ret();
}
void JIT::emit_op_new_array(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_new_array);
......@@ -804,16 +846,6 @@ void JIT::emit_op_resolve(Instruction* currentInstruction)
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_construct_verify(Instruction* currentInstruction)
{
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
emitJumpSlowCaseIfNotJSCell(regT0);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
addSlowCase(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
}
void JIT::emit_op_to_primitive(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
......@@ -1492,14 +1524,6 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
linkSlowCase(iter);
emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment