Commit d4cbcfce authored by dslomov@chromium.org's avatar dslomov@chromium.org

Implement the new semantics for 'super(...)'

Per the latest ES6 draft, super(...) translates into a call
to function's prototype.

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

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24683 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 27b1c823
...@@ -3076,6 +3076,15 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -3076,6 +3076,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitKeyedCallWithLoadIC(expr, property->key()); EmitKeyedCallWithLoadIC(expr, property->key());
} }
} }
} 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);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
} else { } else {
DCHECK(call_type == Call::OTHER_CALL); DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above. // Call to an arbitrary expression not handled specially above.
......
...@@ -2741,6 +2741,15 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2741,6 +2741,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitKeyedCallWithLoadIC(expr, property->key()); EmitKeyedCallWithLoadIC(expr, property->key());
} }
} }
} 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);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
} else { } else {
DCHECK(call_type == Call::OTHER_CALL); DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above. // Call to an arbitrary expression not handled specially above.
......
...@@ -581,6 +581,8 @@ Call::CallType Call::GetCallType(Isolate* isolate) const { ...@@ -581,6 +581,8 @@ Call::CallType Call::GetCallType(Isolate* isolate) const {
} }
} }
if (expression()->AsSuperReference() != NULL) return SUPER_CALL;
Property* property = expression()->AsProperty(); Property* property = expression()->AsProperty();
return property != NULL ? PROPERTY_CALL : OTHER_CALL; return property != NULL ? PROPERTY_CALL : OTHER_CALL;
} }
......
...@@ -1851,6 +1851,7 @@ class Call FINAL : public Expression { ...@@ -1851,6 +1851,7 @@ class Call FINAL : public Expression {
GLOBAL_CALL, GLOBAL_CALL,
LOOKUP_SLOT_CALL, LOOKUP_SLOT_CALL,
PROPERTY_CALL, PROPERTY_CALL,
SUPER_CALL,
OTHER_CALL OTHER_CALL
}; };
...@@ -3474,16 +3475,7 @@ class AstNodeFactory FINAL BASE_EMBEDDED { ...@@ -3474,16 +3475,7 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
Call* NewCall(Expression* expression, Call* NewCall(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
int pos) { int pos) {
SuperReference* super_ref = expression->AsSuperReference(); Call* call = new (zone_) Call(zone_, expression, arguments, pos, id_gen_);
Call* call;
if (super_ref != NULL) {
Literal* constructor =
NewStringLiteral(ast_value_factory_->constructor_string(), pos);
Property* superConstructor = NewProperty(super_ref, constructor, pos);
call = new (zone_) Call(zone_, superConstructor, arguments, pos, id_gen_);
} else {
call = new (zone_) Call(zone_, expression, arguments, pos, id_gen_);
}
VISIT_AND_RETURN(Call, call) VISIT_AND_RETURN(Call, call)
} }
......
...@@ -1261,6 +1261,11 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -1261,6 +1261,11 @@ void AstGraphBuilder::VisitCall(Call* expr) {
flags = CALL_AS_METHOD; flags = CALL_AS_METHOD;
break; break;
} }
case Call::SUPER_CALL: {
// todo(dslomov): implement super calls in turbofan.
UNIMPLEMENTED();
break;
}
case Call::POSSIBLY_EVAL_CALL: case Call::POSSIBLY_EVAL_CALL:
possibly_eval = true; possibly_eval = true;
// Fall through. // Fall through.
......
...@@ -2972,6 +2972,14 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2972,6 +2972,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitKeyedCallWithLoadIC(expr, property->key()); EmitKeyedCallWithLoadIC(expr, property->key());
} }
} }
} 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);
__ push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
} else { } else {
DCHECK(call_type == Call::OTHER_CALL); DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above. // Call to an arbitrary expression not handled specially above.
......
...@@ -2971,6 +2971,14 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2971,6 +2971,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitKeyedCallWithLoadIC(expr, property->key()); EmitKeyedCallWithLoadIC(expr, property->key());
} }
} }
} 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);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
} else { } else {
DCHECK(call_type == Call::OTHER_CALL); DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above. // Call to an arbitrary expression not handled specially above.
......
...@@ -1192,11 +1192,15 @@ ...@@ -1192,11 +1192,15 @@
(function TestSuperCall() { (function TestSuperCall() {
function Subclass(base, constructor) { function Subclass(base, constructor) {
var homeObject = { __proto__ : base.prototype }; var homeObject = {
var result = constructor.toMethod(homeObject); __proto__: base.prototype,
homeObject.constructor = result; constructor: constructor
result.prototype = homeObject; };
return result; constructor.__proto__ = base;
constructor.prototype = homeObject;
// not doing toMethod: home object is not required for
// super constructor calls.
return constructor;
} }
var baseCalled = 0; var baseCalled = 0;
...@@ -1245,6 +1249,40 @@ ...@@ -1245,6 +1249,40 @@
var d = new Derived2("base", "derived"); var d = new Derived2("base", "derived");
assertEquals("base", d.fromBase); assertEquals("base", d.fromBase);
assertEquals("derived", d.fromDerived); assertEquals("derived", d.fromDerived);
function ImplicitSubclassOfFunction() {
super();
this.x = 123;
}
var o = new ImplicitSubclassOfFunction();
assertEquals(123, o.x);
var calls = 0;
function G() {
calls++;
}
function F() {
super();
}
F.__proto__ = G;
new F();
assertEquals(1, calls);
F.__proto__ = function() {};
new F();
assertEquals(1, calls);
}());
(function TestSuperCallErrorCases() {
function T() {
super();
}
T.__proto__ = null;
// Spec says ReferenceError here, but for other IsCallable failures
// we throw TypeError.
// Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
assertThrows(function() { new T(); }, TypeError);
}()); }());
......
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