Implement loads and calls from 'super'
R=verwaest@chromium.org, arv@chromium.org BUG=v8:3330 LOG=N Review URL: https://codereview.chromium.org/527963002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24078 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
33ddb37ba3
commit
e36aacdee2
@ -1355,6 +1355,25 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ ldr(LoadDescriptor::ReceiverRegister(),
|
||||
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
|
||||
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
|
||||
|
||||
__ cmp(r0, Operand(isolate()->factory()->undefined_value()));
|
||||
Label done;
|
||||
__ b(ne, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
@ -2300,6 +2319,7 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
|
||||
__ mov(LoadDescriptor::NameRegister(), Operand(key->value()));
|
||||
if (FLAG_vector_ics) {
|
||||
__ mov(VectorLoadICDescriptor::SlotRegister(),
|
||||
@ -2311,6 +2331,21 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(r0);
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
__ Push(key->value());
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
|
||||
@ -2598,9 +2633,13 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
Expression* key = expr->key();
|
||||
|
||||
if (key->IsPropertyName()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), r0);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), r0);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(r0);
|
||||
} else {
|
||||
@ -2643,6 +2682,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
} else {
|
||||
// Load the function from the receiver.
|
||||
DCHECK(callee->IsProperty());
|
||||
DCHECK(!callee->AsProperty()->IsSuperAccess());
|
||||
__ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
|
||||
EmitNamedPropertyLoad(callee->AsProperty());
|
||||
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
||||
@ -2656,6 +2696,45 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = r1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(r0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(r0);
|
||||
__ ldr(scratch, MemOperand(sp, kPointerSize));
|
||||
__ Push(scratch);
|
||||
__ Push(r0);
|
||||
__ Push(key->value());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - home_object <-- LoadFromSuper will pop here and below.
|
||||
// - this (receiver)
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ str(r0, MemOperand(sp, kPointerSize));
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
// Code common for calls using the IC.
|
||||
void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
Expression* key) {
|
||||
@ -2825,13 +2904,20 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCall(expr);
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (property->key()->IsPropertyName()) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (is_named_call) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
|
@ -1341,6 +1341,26 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ ldr(LoadDescriptor::ReceiverRegister(),
|
||||
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Mov(LoadDescriptor::NameRegister(), Operand(home_object_symbol));
|
||||
|
||||
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
|
||||
|
||||
__ Mov(x10, Operand(isolate()->factory()->undefined_value()));
|
||||
__ cmp(x0, x10);
|
||||
Label done;
|
||||
__ b(&done, ne);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
@ -1949,6 +1969,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!prop->IsSuperAccess());
|
||||
|
||||
__ Mov(LoadDescriptor::NameRegister(), Operand(key->value()));
|
||||
if (FLAG_vector_ics) {
|
||||
__ Mov(VectorLoadICDescriptor::SlotRegister(),
|
||||
@ -1960,6 +1982,21 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(x0);
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
__ Push(key->value());
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
|
||||
@ -2263,9 +2300,13 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
Expression* key = expr->key();
|
||||
|
||||
if (key->IsPropertyName()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), x0);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), x0);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(x0);
|
||||
} else {
|
||||
@ -2307,6 +2348,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
} else {
|
||||
// Load the function from the receiver.
|
||||
DCHECK(callee->IsProperty());
|
||||
DCHECK(!callee->AsProperty()->IsSuperAccess());
|
||||
__ Peek(LoadDescriptor::ReceiverRegister(), 0);
|
||||
EmitNamedPropertyLoad(callee->AsProperty());
|
||||
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
||||
@ -2319,6 +2361,45 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = x10;
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(x0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(x0);
|
||||
__ Peek(scratch, kPointerSize);
|
||||
__ Push(scratch, x0);
|
||||
__ Push(key->value());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - home_object <-- LoadFromSuper will pop here and below.
|
||||
// - this (receiver)
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ Poke(x0, kPointerSize);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
// Code common for calls using the IC.
|
||||
void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
Expression* key) {
|
||||
@ -2491,15 +2572,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCall(expr);
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (property->key()->IsPropertyName()) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (is_named_call) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -402,6 +402,8 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
|
||||
info()->function()->dont_optimize_reason() != kTryFinallyStatement &&
|
||||
// TODO(turbofan): Make ES6 for-of work and remove this bailout.
|
||||
info()->function()->dont_optimize_reason() != kForOfStatement &&
|
||||
// TODO(turbofan): Make super work and remove this bailout.
|
||||
info()->function()->dont_optimize_reason() != kSuperReference &&
|
||||
// TODO(turbofan): Make OSR work and remove this bailout.
|
||||
!info()->is_osr()) {
|
||||
compiler::Pipeline pipeline(info());
|
||||
|
@ -833,8 +833,7 @@ void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitSuperReference(SuperReference* super) {
|
||||
DCHECK(FLAG_harmony_classes);
|
||||
UNIMPLEMENTED();
|
||||
__ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -477,6 +477,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// Platform-specific code sequences for calls
|
||||
void EmitCall(Call* expr, CallICState::CallType = CallICState::FUNCTION);
|
||||
void EmitCallWithLoadIC(Call* expr);
|
||||
void EmitSuperCallWithLoadIC(Call* expr);
|
||||
void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
|
||||
|
||||
// Platform-specific code for inline runtime calls.
|
||||
@ -520,6 +521,8 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// The receiver is left on the stack by the IC.
|
||||
void EmitNamedPropertyLoad(Property* expr);
|
||||
|
||||
void EmitNamedSuperPropertyLoad(Property* expr);
|
||||
|
||||
// Load a value from a keyed property.
|
||||
// The receiver and the key is left on the stack by the IC.
|
||||
void EmitKeyedPropertyLoad(Property* expr);
|
||||
@ -560,6 +563,8 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// accumulator.
|
||||
void EmitKeyedPropertyAssignment(Assignment* expr);
|
||||
|
||||
void EmitLoadHomeObject(SuperReference* expr);
|
||||
|
||||
void CallIC(Handle<Code> code,
|
||||
TypeFeedbackId id = TypeFeedbackId::None());
|
||||
|
||||
|
@ -11215,7 +11215,10 @@ void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) {
|
||||
UNREACHABLE();
|
||||
DCHECK(!HasStackOverflow());
|
||||
DCHECK(current_block() != NULL);
|
||||
DCHECK(current_block()->HasPredecessor());
|
||||
return Bailout(kSuperReference);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1278,6 +1278,25 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ mov(LoadDescriptor::ReceiverRegister(),
|
||||
Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ mov(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
|
||||
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
|
||||
|
||||
__ cmp(eax, isolate()->factory()->undefined_value());
|
||||
Label done;
|
||||
__ j(not_equal, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
@ -2231,6 +2250,21 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ push(eax);
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
__ push(Immediate(key->value()));
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
|
||||
@ -2520,9 +2554,13 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
Expression* key = expr->key();
|
||||
|
||||
if (key->IsPropertyName()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), result_register());
|
||||
EmitNamedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
__ Move(LoadDescriptor::ReceiverRegister(), result_register());
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(eax);
|
||||
} else {
|
||||
@ -2561,6 +2599,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
} else {
|
||||
// Load the function from the receiver.
|
||||
DCHECK(callee->IsProperty());
|
||||
DCHECK(!callee->AsProperty()->IsSuperAccess());
|
||||
__ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
|
||||
EmitNamedPropertyLoad(callee->AsProperty());
|
||||
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
||||
@ -2573,6 +2612,42 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ push(eax);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ push(eax);
|
||||
__ push(Operand(esp, kPointerSize));
|
||||
__ push(eax);
|
||||
__ push(Immediate(key->value()));
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - home_object <-- LoadFromSuper will pop here and below.
|
||||
// - this (receiver)
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ mov(Operand(esp, kPointerSize), eax);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
// Code common for calls using the IC.
|
||||
void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
Expression* key) {
|
||||
@ -2733,15 +2808,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (property->key()->IsPropertyName()) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (is_named_call) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
|
@ -38,6 +38,8 @@ var kMessages = {
|
||||
cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
|
||||
not_constructor: ["%0", " is not a constructor"],
|
||||
not_defined: ["%0", " is not defined"],
|
||||
non_method: ["'super' is referenced from non-method"],
|
||||
unsupported_super: ["Unsupported reference to 'super'"],
|
||||
non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
|
||||
non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
|
||||
with_expression: ["%0", " has no properties"],
|
||||
|
@ -2080,6 +2080,30 @@ RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
|
||||
|
||||
if (home_object->IsAccessCheckNeeded() &&
|
||||
!isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) {
|
||||
isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
}
|
||||
|
||||
PrototypeIterator iter(isolate, home_object);
|
||||
Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
|
||||
if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
|
||||
|
||||
LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsExtensible) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -9544,6 +9568,23 @@ RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewReferenceError("non_method", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
|
@ -183,7 +183,10 @@ namespace internal {
|
||||
\
|
||||
/* Classes support */ \
|
||||
F(ToMethod, 2, 1) \
|
||||
F(HomeObjectSymbol, 0, 1)
|
||||
F(HomeObjectSymbol, 0, 1) \
|
||||
F(ThrowNonMethodError, 0, 1) \
|
||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||
F(LoadFromSuper, 3, 1)
|
||||
|
||||
|
||||
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
|
||||
|
@ -1312,6 +1312,25 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ movp(LoadDescriptor::ReceiverRegister(),
|
||||
Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
|
||||
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
|
||||
|
||||
__ Cmp(rax, isolate()->factory()->undefined_value());
|
||||
Label done;
|
||||
__ j(not_equal, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
@ -2263,6 +2282,21 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(rax);
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
__ Push(key->value());
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
SetSourcePosition(prop->position());
|
||||
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
|
||||
@ -2513,10 +2547,14 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
Expression* key = expr->key();
|
||||
|
||||
if (key->IsPropertyName()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
DCHECK(!rax.is(LoadDescriptor::ReceiverRegister()));
|
||||
__ movp(LoadDescriptor::ReceiverRegister(), rax);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForAccumulatorValue(expr->obj());
|
||||
DCHECK(!rax.is(LoadDescriptor::ReceiverRegister()));
|
||||
__ movp(LoadDescriptor::ReceiverRegister(), rax);
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(rax);
|
||||
} else {
|
||||
@ -2555,6 +2593,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
} else {
|
||||
// Load the function from the receiver.
|
||||
DCHECK(callee->IsProperty());
|
||||
DCHECK(!callee->AsProperty()->IsSuperAccess());
|
||||
__ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
|
||||
EmitNamedPropertyLoad(callee->AsProperty());
|
||||
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
||||
@ -2567,6 +2606,43 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(rax);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(rax);
|
||||
__ Push(Operand(rsp, kPointerSize));
|
||||
__ Push(rax);
|
||||
__ Push(key->value());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - home_object <-- LoadFromSuper will pop here and below.
|
||||
// - this (receiver)
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ movp(Operand(rsp, kPointerSize), rax);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
// Common code for calls using the IC.
|
||||
void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
Expression* key) {
|
||||
@ -2728,13 +2804,20 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCall(expr);
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (property->key()->IsPropertyName()) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (is_named_call) {
|
||||
EmitCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithLoadIC(expr, property->key());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DCHECK(call_type == Call::OTHER_CALL);
|
||||
|
@ -9543,18 +9543,14 @@ TEST(AccessControlES5) {
|
||||
}
|
||||
|
||||
|
||||
static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
|
||||
Local<Value> name,
|
||||
v8::AccessType type,
|
||||
Local<Value> data) {
|
||||
static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
|
||||
v8::AccessType type, Local<Value> data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
|
||||
uint32_t key,
|
||||
v8::AccessType type,
|
||||
Local<Value> data) {
|
||||
static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
|
||||
v8::AccessType type, Local<Value> data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -9566,8 +9562,8 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) {
|
||||
v8::ObjectTemplate::New(isolate);
|
||||
|
||||
obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
|
||||
obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
|
||||
GetOwnPropertyNamesIndexedBlocker);
|
||||
obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
|
||||
BlockEverythingIndexed);
|
||||
|
||||
// Create an environment
|
||||
v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
|
||||
@ -9602,6 +9598,26 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) {
|
||||
}
|
||||
|
||||
|
||||
TEST(SuperAccessControl) {
|
||||
i::FLAG_harmony_classes = true;
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::ObjectTemplate> obj_template =
|
||||
v8::ObjectTemplate::New(isolate);
|
||||
obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
|
||||
BlockEverythingIndexed);
|
||||
LocalContext env;
|
||||
env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
|
||||
|
||||
v8::TryCatch try_catch;
|
||||
CompileRun(
|
||||
"function f() { return super.hasOwnProperty; };"
|
||||
"var m = f.toMethod(prohibited);"
|
||||
"m();");
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
|
||||
static void IndexedPropertyEnumerator(
|
||||
const v8::PropertyCallbackInfo<v8::Array>& info) {
|
||||
v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
|
||||
|
127
test/mjsunit/harmony/super.js
Normal file
127
test/mjsunit/harmony/super.js
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-classes
|
||||
|
||||
|
||||
(function TestSuperNamedLoads() {
|
||||
function Base() { }
|
||||
function Derived() {
|
||||
this.derivedDataProperty = "xxx";
|
||||
}
|
||||
Derived.prototype = Object.create(Base.prototype);
|
||||
|
||||
function fBase() { return "Base " + this.toString(); }
|
||||
|
||||
Base.prototype.f = fBase.toMethod(Base.prototype);
|
||||
|
||||
function fDerived() {
|
||||
assertEquals("Base this is Derived", super.f());
|
||||
assertEquals(15, super.x);
|
||||
assertEquals(27, this.x);
|
||||
|
||||
return "Derived"
|
||||
}
|
||||
|
||||
Base.prototype.x = 15;
|
||||
Base.prototype.toString = function() { return "this is Base"; };
|
||||
Derived.prototype.toString = function() { return "this is Derived"; };
|
||||
Derived.prototype.x = 27;
|
||||
Derived.prototype.f = fDerived.toMethod(Derived.prototype);
|
||||
|
||||
assertEquals("Base this is Base", new Base().f());
|
||||
assertEquals("Derived", new Derived().f());
|
||||
}());
|
||||
|
||||
(function TestSuperKeywordNonMethod() {
|
||||
function f() {
|
||||
super.unknown();
|
||||
}
|
||||
|
||||
assertThrows(f, ReferenceError);
|
||||
}());
|
||||
|
||||
|
||||
(function TestGetter() {
|
||||
function Base() {}
|
||||
var derived;
|
||||
Base.prototype = {
|
||||
constructor: Base,
|
||||
get x() {
|
||||
assertSame(this, derived);
|
||||
return this._x;
|
||||
},
|
||||
_x: 'base'
|
||||
};
|
||||
|
||||
function Derived() {}
|
||||
Derived.__proto__ = Base;
|
||||
Derived.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
constructor: Derived,
|
||||
_x: 'derived'
|
||||
};
|
||||
Derived.prototype.testGetter = function() {
|
||||
return super.x;
|
||||
}.toMethod(Derived.prototype);
|
||||
derived = new Derived();
|
||||
assertEquals('derived', derived.testGetter());
|
||||
}());
|
||||
|
||||
/*
|
||||
* TODO[dslomov]: named stores and keyed loads/stores not implemented yet.
|
||||
(function TestSetter() {
|
||||
function Base() {}
|
||||
Base.prototype = {
|
||||
constructor: Base,
|
||||
get x() {
|
||||
return this._x;
|
||||
},
|
||||
set x(v) {
|
||||
this._x = v;
|
||||
},
|
||||
_x: 'base'
|
||||
};
|
||||
|
||||
function Derived() {}
|
||||
Derived.__proto__ = Base;
|
||||
Derived.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
constructor: Derived,
|
||||
_x: 'derived'
|
||||
};
|
||||
Derived.prototype.testSetter = function() {
|
||||
super.x = 'foobar';
|
||||
}.toMethod(Derived.prototype);
|
||||
var d = new Derived();
|
||||
d.testSetter();
|
||||
assertEquals('base', Base.prototype._x);
|
||||
assertEquals('foobar', d._x);
|
||||
}());
|
||||
|
||||
|
||||
(function TestKeyedGetter() {
|
||||
function Base() {}
|
||||
Base.prototype = {
|
||||
constructor: Base,
|
||||
_x: 'base'
|
||||
};
|
||||
|
||||
Object.defineProperty(Base.prototype, '0',
|
||||
{ get: function() { return this._x; } });
|
||||
|
||||
function Derived() {}
|
||||
Derived.__proto__ = Base;
|
||||
Derived.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
constructor: Derived,
|
||||
_x: 'derived'
|
||||
};
|
||||
Derived.prototype.testGetter = function() {
|
||||
return super[0];
|
||||
}.toMethod(Derived.prototype);
|
||||
assertEquals('derived', new Derived()[0]);
|
||||
// assertEquals('derived', new Derived().testGetter());
|
||||
}());
|
||||
*/
|
7
test/mjsunit/runtime-gen/loadfromsuper.js
Normal file
7
test/mjsunit/runtime-gen/loadfromsuper.js
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
|
||||
// Flags: --allow-natives-syntax --harmony --harmony-proxies
|
||||
var _home_object = new Object();
|
||||
var _receiver = new Object();
|
||||
var _name = "name";
|
||||
%LoadFromSuper(_home_object, _receiver, _name);
|
Loading…
Reference in New Issue
Block a user