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:
parent
ea3a205af2
commit
99cafa0d5a
@ -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) {
|
||||
#ifdef DEBUG
|
||||
// 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) {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
DCHECK(super_ref != NULL);
|
||||
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ Push(r0);
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
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
|
||||
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
||||
// ignored.
|
||||
VisitForStackValue(expr->expression());
|
||||
if (expr->expression()->IsSuperReference()) {
|
||||
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
} else {
|
||||
VisitForStackValue(expr->expression());
|
||||
}
|
||||
|
||||
// Push the arguments ("left-to-right") on the stack.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -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) {
|
||||
#ifdef DEBUG
|
||||
// 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) {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
DCHECK(super_ref != NULL);
|
||||
__ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ Push(x0);
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
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
|
||||
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
||||
// ignored.
|
||||
VisitForStackValue(expr->expression());
|
||||
if (expr->expression()->IsSuperReference()) {
|
||||
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
} else {
|
||||
VisitForStackValue(expr->expression());
|
||||
}
|
||||
|
||||
// Push the arguments ("left-to-right") on the stack.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -609,6 +609,8 @@ class FullCodeGenerator: public AstVisitor {
|
||||
|
||||
void EmitLoadHomeObject(SuperReference* expr);
|
||||
|
||||
void EmitLoadSuperConstructor(SuperReference* expr);
|
||||
|
||||
void CallIC(Handle<Code> code,
|
||||
TypeFeedbackId id = TypeFeedbackId::None());
|
||||
|
||||
|
@ -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) {
|
||||
#ifdef DEBUG
|
||||
// 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) {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
DCHECK(super_ref != NULL);
|
||||
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
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
|
||||
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
||||
// ignored.
|
||||
VisitForStackValue(expr->expression());
|
||||
if (expr->expression()->IsSuperReference()) {
|
||||
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
} else {
|
||||
VisitForStackValue(expr->expression());
|
||||
}
|
||||
|
||||
// Push the arguments ("left-to-right") on the stack.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -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) {
|
||||
#ifdef DEBUG
|
||||
// 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) {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
DCHECK(super_ref != NULL);
|
||||
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
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
|
||||
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
||||
// ignored.
|
||||
VisitForStackValue(expr->expression());
|
||||
if (expr->expression()->IsSuperReference()) {
|
||||
EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
} else {
|
||||
VisitForStackValue(expr->expression());
|
||||
}
|
||||
|
||||
// Push the arguments ("left-to-right") on the stack.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -1735,19 +1735,19 @@
|
||||
}());
|
||||
|
||||
|
||||
(function TestSuperCall() {
|
||||
function Subclass(base, constructor) {
|
||||
var homeObject = {
|
||||
__proto__: base.prototype,
|
||||
constructor: constructor
|
||||
};
|
||||
constructor.__proto__ = base;
|
||||
constructor.prototype = homeObject;
|
||||
// not doing toMethod: home object is not required for
|
||||
// super constructor calls.
|
||||
return constructor;
|
||||
}
|
||||
function Subclass(base, constructor) {
|
||||
var homeObject = {
|
||||
__proto__: base.prototype,
|
||||
constructor: constructor
|
||||
};
|
||||
constructor.__proto__ = base;
|
||||
constructor.prototype = homeObject;
|
||||
// not doing toMethod: home object is not required for
|
||||
// super constructor calls.
|
||||
return constructor;
|
||||
}
|
||||
|
||||
(function TestSuperCall() {
|
||||
var baseCalled = 0;
|
||||
var derivedCalled = 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 T() {
|
||||
super();
|
||||
@ -1828,4 +1854,10 @@
|
||||
// we throw TypeError.
|
||||
// Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
|
||||
assertThrows(function() { new T(); }, TypeError);
|
||||
|
||||
function T1() {
|
||||
var b = new super();
|
||||
}
|
||||
T1.__proto = null;
|
||||
assertThrows(function() { new T1(); }, TypeError);
|
||||
}());
|
||||
|
Loading…
Reference in New Issue
Block a user