Classes: implement 'new super'.

R=ishell@chromium.org, arv@chromium.org
BUG=v8:3330
LOG=N

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24822 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
dslomov@chromium.org 2014-10-23 08:11:51 +00:00
parent ea3a205af2
commit 99cafa0d5a
6 changed files with 104 additions and 30 deletions

View File

@ -2964,6 +2964,14 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
} }
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* expr) {
DCHECK(super_ref != NULL);
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(r0);
__ CallRuntime(Runtime::kGetPrototype, 1);
}
void FullCodeGenerator::VisitCall(Call* expr) { void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG #ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths // We want to verify that RecordJSReturnSite gets called on all paths
@ -3081,10 +3089,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} }
} else if (call_type == Call::SUPER_CALL) { } else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference(); SuperReference* super_ref = callee->AsSuperReference();
DCHECK(super_ref != NULL); EmitLoadSuperConstructor(super_ref);
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(r0);
__ CallRuntime(Runtime::kGetPrototype, 1);
__ Push(result_register()); __ Push(result_register());
VisitForStackValue(super_ref->this_var()); VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD); EmitCall(expr, CallICState::METHOD);
@ -3116,7 +3121,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// Push constructor on the stack. If it's not a function it's used as // Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored. // ignored.
if (expr->expression()->IsSuperReference()) {
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
__ Push(result_register());
} else {
VisitForStackValue(expr->expression()); VisitForStackValue(expr->expression());
}
// Push the arguments ("left-to-right") on the stack. // Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();

View File

@ -2628,6 +2628,14 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
} }
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* expr) {
DCHECK(super_ref != NULL);
__ ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(x0);
__ CallRuntime(Runtime::kGetPrototype, 1);
}
void FullCodeGenerator::VisitCall(Call* expr) { void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG #ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths // We want to verify that RecordJSReturnSite gets called on all paths
@ -2746,10 +2754,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} }
} else if (call_type == Call::SUPER_CALL) { } else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference(); SuperReference* super_ref = callee->AsSuperReference();
DCHECK(super_ref != NULL); EmitLoadSuperConstructor(super_ref);
__ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(x0);
__ CallRuntime(Runtime::kGetPrototype, 1);
__ Push(result_register()); __ Push(result_register());
VisitForStackValue(super_ref->this_var()); VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD); EmitCall(expr, CallICState::METHOD);
@ -2781,7 +2786,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// Push constructor on the stack. If it's not a function it's used as // Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored. // ignored.
if (expr->expression()->IsSuperReference()) {
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
__ Push(result_register());
} else {
VisitForStackValue(expr->expression()); VisitForStackValue(expr->expression());
}
// Push the arguments ("left-to-right") on the stack. // Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();

View File

@ -609,6 +609,8 @@ class FullCodeGenerator: public AstVisitor {
void EmitLoadHomeObject(SuperReference* expr); void EmitLoadHomeObject(SuperReference* expr);
void EmitLoadSuperConstructor(SuperReference* expr);
void CallIC(Handle<Code> code, void CallIC(Handle<Code> code,
TypeFeedbackId id = TypeFeedbackId::None()); TypeFeedbackId id = TypeFeedbackId::None());

View File

@ -2867,6 +2867,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
} }
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* expr) {
DCHECK(super_ref != NULL);
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
}
void FullCodeGenerator::VisitCall(Call* expr) { void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG #ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths // We want to verify that RecordJSReturnSite gets called on all paths
@ -2977,9 +2984,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} }
} else if (call_type == Call::SUPER_CALL) { } else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference(); SuperReference* super_ref = callee->AsSuperReference();
DCHECK(super_ref != NULL); EmitLoadSuperConstructor(super_ref);
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
__ push(result_register()); __ push(result_register());
VisitForStackValue(super_ref->this_var()); VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD); EmitCall(expr, CallICState::METHOD);
@ -3010,7 +3015,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// Push constructor on the stack. If it's not a function it's used as // Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored. // ignored.
if (expr->expression()->IsSuperReference()) {
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
__ push(result_register());
} else {
VisitForStackValue(expr->expression()); VisitForStackValue(expr->expression());
}
// Push the arguments ("left-to-right") on the stack. // Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();

View File

@ -2867,6 +2867,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
} }
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* expr) {
DCHECK(super_ref != NULL);
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
}
void FullCodeGenerator::VisitCall(Call* expr) { void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG #ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths // We want to verify that RecordJSReturnSite gets called on all paths
@ -2976,9 +2983,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} }
} else if (call_type == Call::SUPER_CALL) { } else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference(); SuperReference* super_ref = callee->AsSuperReference();
DCHECK(super_ref != NULL); EmitLoadSuperConstructor(super_ref);
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
__ Push(result_register()); __ Push(result_register());
VisitForStackValue(super_ref->this_var()); VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD); EmitCall(expr, CallICState::METHOD);
@ -3009,7 +3014,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// Push constructor on the stack. If it's not a function it's used as // Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored. // ignored.
if (expr->expression()->IsSuperReference()) {
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
__ Push(result_register());
} else {
VisitForStackValue(expr->expression()); VisitForStackValue(expr->expression());
}
// Push the arguments ("left-to-right") on the stack. // Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();

View File

@ -1735,7 +1735,6 @@
}()); }());
(function TestSuperCall() {
function Subclass(base, constructor) { function Subclass(base, constructor) {
var homeObject = { var homeObject = {
__proto__: base.prototype, __proto__: base.prototype,
@ -1748,6 +1747,7 @@
return constructor; return constructor;
} }
(function TestSuperCall() {
var baseCalled = 0; var baseCalled = 0;
var derivedCalled = 0; var derivedCalled = 0;
var derivedDerivedCalled = 0; var derivedDerivedCalled = 0;
@ -1819,6 +1819,32 @@
}()); }());
(function TestNewSuper() {
var baseCalled = 0;
var derivedCalled = 0;
function Base() {
baseCalled++;
this.x = 15;
}
var Derived = Subclass(Base, function() {
baseCalled = 0;
var b = new super();
assertEquals(1, baseCalled)
assertEquals(Base.prototype, b.__proto__);
assertEquals(15, b.x);
assertEquals(undefined, this.x);
derivedCalled++;
});
derivedCalled = 0;
new Derived();
assertEquals(1, derivedCalled);
}());
(function TestSuperCallErrorCases() { (function TestSuperCallErrorCases() {
function T() { function T() {
super(); super();
@ -1828,4 +1854,10 @@
// we throw TypeError. // we throw TypeError.
// Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282 // Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
assertThrows(function() { new T(); }, TypeError); assertThrows(function() { new T(); }, TypeError);
function T1() {
var b = new super();
}
T1.__proto = null;
assertThrows(function() { new T1(); }, TypeError);
}()); }());