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:
dslomov@chromium.org 2014-09-19 11:08:04 +00:00
parent 33ddb37ba3
commit e36aacdee2
14 changed files with 595 additions and 53 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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());

View File

@ -833,8 +833,7 @@ void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
void FullCodeGenerator::VisitSuperReference(SuperReference* super) {
DCHECK(FLAG_harmony_classes);
UNIMPLEMENTED();
__ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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.

View File

@ -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"],

View File

@ -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);

View File

@ -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) \

View File

@ -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);

View File

@ -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);

View 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());
}());
*/

View 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);