MIPS: new classes: special construct stub for derived classs and TDZ for this.

Port 6f97a4948f

BUG=

Review URL: https://codereview.chromium.org/895243002

Cr-Commit-Position: refs/heads/master@{#26417}
This commit is contained in:
akos.palfi 2015-02-03 17:51:56 -08:00 committed by Commit bot
parent 600474ad44
commit 6b30ef8e3e
4 changed files with 167 additions and 4 deletions

View File

@ -758,6 +758,73 @@ void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
}
void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
// -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
// TODO(dslomov): support pretenuring
CHECK(!FLAG_pretenuring_call_new);
{
FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
__ mov(t0, a0);
__ SmiTag(t0);
__ push(t0); // Smi-tagged arguments count.
// receiver is the hole.
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ push(at);
// Set up pointer to last argument.
__ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Copy arguments and receiver to the expression stack.
// a0: number of arguments
// a1: constructor function
// a2: address of last argument (caller sp)
// t0: number of arguments (smi-tagged)
// sp[0]: receiver
// sp[1]: number of arguments (smi-tagged)
Label loop, entry;
__ Branch(&entry);
__ bind(&loop);
__ sll(at, t0, kPointerSizeLog2 - 1);
__ Addu(at, a2, Operand(at));
__ lw(at, MemOperand(at));
__ push(at);
__ bind(&entry);
__ Subu(t0, t0, Operand(2));
__ Branch(&loop, ge, t0, Operand(zero_reg));
// Call the function.
// a0: number of arguments
// a1: constructor function
ParameterCount actual(a0);
__ InvokeFunction(a1, actual, CALL_FUNCTION, NullCallWrapper());
// Restore context from the frame.
// v0: result
// sp[0]: number of arguments (smi-tagged)
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ lw(a1, MemOperand(sp, 0));
// Leave construct frame.
}
__ sll(at, a1, kPointerSizeLog2 - 1);
__ Addu(sp, sp, Operand(at));
__ Addu(sp, sp, Operand(kPointerSize));
__ Jump(ra);
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from JSEntryStub::GenerateBody

View File

@ -1521,6 +1521,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
} else if (var->is_this()) {
CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
// TODO(dslomov): implement 'this' hole check elimination.
skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
@ -3222,6 +3226,17 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
Variable* this_var = super_ref->this_var()->var();
GetVar(a0, this_var);
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
Label uninitialized_this;
__ Branch(&uninitialized_this, eq, a0, Operand(at));
__ li(a0, Operand(this_var->name()));
__ Push(a0);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&uninitialized_this);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
@ -3256,8 +3271,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
RecordJSReturnSite(expr);
// TODO(dslomov): implement TDZ for `this`.
EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(v0);
}

View File

@ -767,6 +767,74 @@ void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
}
void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
// -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
// TODO(dslomov): support pretenuring
CHECK(!FLAG_pretenuring_call_new);
{
FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
__ mov(a4, a0);
__ SmiTag(a4);
__ push(a4); // Smi-tagged arguments count.
// receiver is the hole.
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ push(at);
// Set up pointer to last argument.
__ Daddu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Copy arguments and receiver to the expression stack.
// a0: number of arguments
// a1: constructor function
// a2: address of last argument (caller sp)
// a4: number of arguments (smi-tagged)
// sp[0]: receiver
// sp[1]: number of arguments (smi-tagged)
Label loop, entry;
__ SmiUntag(a4);
__ jmp(&entry);
__ bind(&loop);
__ dsll(at, a4, kPointerSizeLog2);
__ Daddu(at, a2, Operand(at));
__ ld(at, MemOperand(at));
__ push(at);
__ bind(&entry);
__ Daddu(a4, a4, Operand(-1));
__ Branch(&loop, ge, a4, Operand(zero_reg));
// Call the function.
// a0: number of arguments
// a1: constructor function
ParameterCount actual(a0);
__ InvokeFunction(a1, actual, CALL_FUNCTION, NullCallWrapper());
// Restore context from the frame.
// v0: result
// sp[0]: number of arguments (smi-tagged)
__ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ ld(a1, MemOperand(sp, 0));
// Leave construct frame.
}
__ SmiScale(at, a1, kPointerSizeLog2);
__ Daddu(sp, sp, Operand(at));
__ Daddu(sp, sp, Operand(kPointerSize));
__ Jump(ra);
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from JSEntryStub::GenerateBody

View File

@ -1518,6 +1518,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
} else if (var->is_this()) {
CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
// TODO(dslomov): implement 'this' hole check elimination.
skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
@ -3220,6 +3224,17 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
Variable* this_var = super_ref->this_var()->var();
GetVar(a0, this_var);
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
Label uninitialized_this;
__ Branch(&uninitialized_this, eq, a0, Operand(at));
__ li(a0, Operand(this_var->name()));
__ Push(a0);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&uninitialized_this);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
@ -3254,8 +3269,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
RecordJSReturnSite(expr);
// TODO(dslomov): implement TDZ for `this`.
EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(v0);
}