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
This commit is contained in:
parent
27b1c823ce
commit
d4cbcfce6e
@ -3076,6 +3076,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
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 {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -2741,6 +2741,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
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 {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -581,6 +581,8 @@ Call::CallType Call::GetCallType(Isolate* isolate) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (expression()->AsSuperReference() != NULL) return SUPER_CALL;
|
||||
|
||||
Property* property = expression()->AsProperty();
|
||||
return property != NULL ? PROPERTY_CALL : OTHER_CALL;
|
||||
}
|
||||
|
12
src/ast.h
12
src/ast.h
@ -1851,6 +1851,7 @@ class Call FINAL : public Expression {
|
||||
GLOBAL_CALL,
|
||||
LOOKUP_SLOT_CALL,
|
||||
PROPERTY_CALL,
|
||||
SUPER_CALL,
|
||||
OTHER_CALL
|
||||
};
|
||||
|
||||
@ -3474,16 +3475,7 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
|
||||
Call* NewCall(Expression* expression,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos) {
|
||||
SuperReference* super_ref = expression->AsSuperReference();
|
||||
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_);
|
||||
}
|
||||
Call* call = new (zone_) Call(zone_, expression, arguments, pos, id_gen_);
|
||||
VISIT_AND_RETURN(Call, call)
|
||||
}
|
||||
|
||||
|
@ -1261,6 +1261,11 @@ void AstGraphBuilder::VisitCall(Call* expr) {
|
||||
flags = CALL_AS_METHOD;
|
||||
break;
|
||||
}
|
||||
case Call::SUPER_CALL: {
|
||||
// todo(dslomov): implement super calls in turbofan.
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
case Call::POSSIBLY_EVAL_CALL:
|
||||
possibly_eval = true;
|
||||
// Fall through.
|
||||
|
@ -2972,6 +2972,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
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 {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -2971,6 +2971,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
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 {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -1192,11 +1192,15 @@
|
||||
|
||||
(function TestSuperCall() {
|
||||
function Subclass(base, constructor) {
|
||||
var homeObject = { __proto__ : base.prototype };
|
||||
var result = constructor.toMethod(homeObject);
|
||||
homeObject.constructor = result;
|
||||
result.prototype = homeObject;
|
||||
return result;
|
||||
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;
|
||||
}
|
||||
|
||||
var baseCalled = 0;
|
||||
@ -1245,6 +1249,40 @@
|
||||
var d = new Derived2("base", "derived");
|
||||
assertEquals("base", d.fromBase);
|
||||
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);
|
||||
}());
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user