Support for super keyed loads where key is a name.
R=arv@chromium.org, ishell@chromium.org BUG=v8:3330 LOG=N Review URL: https://codereview.chromium.org/622523004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24403 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
955876b5f3
commit
da86ab5d23
@ -2382,6 +2382,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
|
||||
// Stack: receiver, home_object, key.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
||||
Token::Value op,
|
||||
OverwriteMode mode,
|
||||
@ -2685,11 +2693,19 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(r0);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), r0);
|
||||
__ pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), r0);
|
||||
__ pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
context()->Plug(r0);
|
||||
}
|
||||
}
|
||||
@ -2801,6 +2817,43 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
// 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);
|
||||
__ Push(r0);
|
||||
__ ldr(scratch, MemOperand(sp, kPointerSize * 2));
|
||||
__ Push(scratch);
|
||||
VisitForStackValue(prop->key());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
|
||||
// - home_object
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ str(r0, MemOperand(sp, kPointerSize));
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
|
||||
// Load the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
@ -2950,9 +3003,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
if (property->IsSuperAccess()) {
|
||||
if (is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedSuperCallWithLoadIC(expr);
|
||||
}
|
||||
} else {
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
|
@ -2032,6 +2032,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
|
||||
// Stack: receiver, home_object, key.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
||||
Token::Value op,
|
||||
OverwriteMode mode,
|
||||
@ -2350,11 +2358,19 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(x0);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), x0);
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), x0);
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
context()->Plug(x0);
|
||||
}
|
||||
}
|
||||
@ -2463,6 +2479,43 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
// 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(x0, scratch);
|
||||
VisitForStackValue(prop->key());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
|
||||
// - home_object
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ Poke(x0, kPointerSize);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
|
||||
// Load the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
@ -2616,9 +2669,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
if (property->IsSuperAccess()) {
|
||||
if (is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedSuperCallWithLoadIC(expr);
|
||||
}
|
||||
} else {
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
|
@ -479,6 +479,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
void EmitCallWithLoadIC(Call* expr);
|
||||
void EmitSuperCallWithLoadIC(Call* expr);
|
||||
void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
|
||||
void EmitKeyedSuperCallWithLoadIC(Call* expr);
|
||||
|
||||
// Platform-specific code for inline runtime calls.
|
||||
InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
|
||||
@ -525,6 +526,10 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// Expect receiver ('this' value) and home_object on the stack.
|
||||
void EmitNamedSuperPropertyLoad(Property* expr);
|
||||
|
||||
// Load a value from super[keyed] property.
|
||||
// Expect receiver ('this' value), home_object and key on the stack.
|
||||
void EmitKeyedSuperPropertyLoad(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);
|
||||
|
@ -2300,6 +2300,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
|
||||
// Stack: receiver, home_object, key.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
||||
Token::Value op,
|
||||
OverwriteMode mode,
|
||||
@ -2605,11 +2613,19 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(eax);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ pop(LoadDescriptor::ReceiverRegister()); // Object.
|
||||
__ Move(LoadDescriptor::NameRegister(), result_register()); // Key.
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ pop(LoadDescriptor::ReceiverRegister()); // Object.
|
||||
__ Move(LoadDescriptor::NameRegister(), result_register()); // Key.
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
context()->Plug(eax);
|
||||
}
|
||||
}
|
||||
@ -2712,6 +2728,40 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
// 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(eax);
|
||||
__ push(Operand(esp, kPointerSize * 2));
|
||||
VisitForStackValue(prop->key());
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
|
||||
// - home_object
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ mov(Operand(esp, kPointerSize), eax);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
|
||||
// Load the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
@ -2853,9 +2903,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
if (property->IsSuperAccess()) {
|
||||
if (is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedSuperCallWithLoadIC(expr);
|
||||
}
|
||||
} else {
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
|
@ -16,6 +16,28 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewReferenceError("non_method", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
static Object* ThrowUnsupportedSuper(Isolate* isolate) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
return ThrowUnsupportedSuper(isolate);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ToMethod) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
@ -35,13 +57,8 @@ RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
|
||||
|
||||
static Object* LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
|
||||
Handle<JSObject> home_object, Handle<Name> name) {
|
||||
if (home_object->IsAccessCheckNeeded() &&
|
||||
!isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) {
|
||||
isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
|
||||
@ -59,6 +76,35 @@ RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
|
||||
|
||||
return LoadFromSuper(isolate, receiver, home_object, name);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
|
||||
|
||||
Handle<Name> name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||
Runtime::ToName(isolate, key));
|
||||
uint32_t index;
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
return ThrowUnsupportedSuper(isolate);
|
||||
}
|
||||
return LoadFromSuper(isolate, receiver, home_object, name);
|
||||
}
|
||||
|
||||
|
||||
static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
|
||||
Handle<Object> receiver, Handle<Name> name,
|
||||
Handle<Object> value, StrictMode strict_mode) {
|
||||
|
@ -463,8 +463,7 @@ MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
MUST_USE_RESULT
|
||||
static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
|
||||
MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) {
|
||||
if (key->IsName()) {
|
||||
return Handle<Name>::cast(key);
|
||||
} else {
|
||||
@ -1742,23 +1741,6 @@ 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_PromiseRejectEvent) {
|
||||
DCHECK(args.length() == 3);
|
||||
HandleScope scope(isolate);
|
||||
|
@ -190,6 +190,7 @@ namespace internal {
|
||||
F(ThrowNonMethodError, 0, 1) \
|
||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||
F(LoadFromSuper, 3, 1) \
|
||||
F(LoadKeyedFromSuper, 3, 1) \
|
||||
F(StoreToSuper_Strict, 4, 1) \
|
||||
F(StoreToSuper_Sloppy, 4, 1)
|
||||
|
||||
@ -852,6 +853,9 @@ class Runtime : public AllStatic {
|
||||
MUST_USE_RESULT static MaybeHandle<Object> GetObjectProperty(
|
||||
Isolate* isolate, Handle<Object> object, Handle<Object> key);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Name> ToName(Isolate* isolate,
|
||||
Handle<Object> key);
|
||||
|
||||
static void SetupArrayBuffer(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> array_buffer,
|
||||
bool is_external, void* data,
|
||||
|
@ -2332,6 +2332,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
|
||||
// Stack: receiver, home_object, key.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
||||
Token::Value op,
|
||||
OverwriteMode mode,
|
||||
@ -2599,11 +2607,19 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
PrepareForBailoutForId(expr->LoadId(), TOS_REG);
|
||||
context()->Plug(rax);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), rax);
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
if (!expr->IsSuperAccess()) {
|
||||
VisitForStackValue(expr->obj());
|
||||
VisitForAccumulatorValue(expr->key());
|
||||
__ Move(LoadDescriptor::NameRegister(), rax);
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
context()->Plug(rax);
|
||||
}
|
||||
}
|
||||
@ -2707,6 +2723,41 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
DCHECK(callee->IsProperty());
|
||||
Property* prop = callee->AsProperty();
|
||||
DCHECK(prop->IsSuperAccess());
|
||||
|
||||
SetSourcePosition(prop->position());
|
||||
// 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(rax);
|
||||
__ Push(Operand(rsp, kPointerSize * 2));
|
||||
VisitForStackValue(prop->key());
|
||||
|
||||
// Stack here:
|
||||
// - home_object
|
||||
// - this (receiver)
|
||||
// - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
|
||||
// - home_object
|
||||
// - key
|
||||
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
|
||||
|
||||
// Replace home_object with target function.
|
||||
__ movp(Operand(rsp, kPointerSize), rax);
|
||||
|
||||
// Stack here:
|
||||
// - target function
|
||||
// - this (receiver)
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
|
||||
// Load the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
@ -2849,9 +2900,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
} else if (call_type == Call::PROPERTY_CALL) {
|
||||
Property* property = callee->AsProperty();
|
||||
bool is_named_call = property->key()->IsPropertyName();
|
||||
// super.x() is handled in EmitCallWithLoadIC.
|
||||
if (property->IsSuperAccess() && is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
if (property->IsSuperAccess()) {
|
||||
if (is_named_call) {
|
||||
EmitSuperCallWithLoadIC(expr);
|
||||
} else {
|
||||
EmitKeyedSuperCallWithLoadIC(expr);
|
||||
}
|
||||
} else {
|
||||
{
|
||||
PreservePositionScope scope(masm()->positions_recorder());
|
||||
|
@ -37,6 +37,41 @@
|
||||
}());
|
||||
|
||||
|
||||
(function TestSuperKeyedLoads() {
|
||||
var x = 'x';
|
||||
var derivedDataProperty = 'derivedDataProperty';
|
||||
var f = 'f';
|
||||
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]());
|
||||
var a = super[x];
|
||||
assertEquals(15, a);
|
||||
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();
|
||||
@ -79,6 +114,80 @@
|
||||
}());
|
||||
|
||||
|
||||
(function TestGetterKeyed() {
|
||||
var x = 'x';
|
||||
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.prototype.testGetterStrict = function() {
|
||||
'use strict';
|
||||
return super[x];
|
||||
}.toMethod(Derived.prototype);
|
||||
Derived.prototype.testGetterWithToString = function() {
|
||||
var toStringCalled;
|
||||
var o = { toString: function() {
|
||||
toStringCalled++;
|
||||
return 'x';
|
||||
} };
|
||||
|
||||
toStringCalled = 0;
|
||||
assertEquals('derived', super[o]);
|
||||
assertEquals(1, toStringCalled);
|
||||
|
||||
var eToThrow = new Error();
|
||||
var oThrowsInToString = { toString: function() {
|
||||
throw eToThrow;
|
||||
} };
|
||||
|
||||
var ex = null;
|
||||
try {
|
||||
super[oThrowsInToString];
|
||||
} catch(e) { ex = e }
|
||||
assertEquals(eToThrow, ex);
|
||||
|
||||
var oReturnsNumericString = { toString: function() {
|
||||
return "1";
|
||||
} };
|
||||
|
||||
ex = null;
|
||||
try {
|
||||
super[oReturnsNumericString];
|
||||
} catch(e) { ex = e }
|
||||
assertTrue(ex instanceof ReferenceError);
|
||||
|
||||
ex = null;
|
||||
try {
|
||||
super[1]; // Indexed properties unsupported yet.
|
||||
} catch (e) { ex = e; }
|
||||
assertTrue(ex instanceof ReferenceError);
|
||||
}.toMethod(Derived.prototype);
|
||||
derived = new Derived();
|
||||
assertEquals('derived', derived.testGetter());
|
||||
derived = new Derived();
|
||||
assertEquals('derived', derived.testGetterStrict());
|
||||
derived = new Derived();
|
||||
derived.testGetterWithToString();
|
||||
}());
|
||||
|
||||
|
||||
(function TestSetter() {
|
||||
function Base() {}
|
||||
Base.prototype = {
|
||||
@ -536,6 +645,6 @@
|
||||
function f1(x) { return super[x]; }
|
||||
function f2(x) { super[x] = 5; }
|
||||
var o = {};
|
||||
assertThrows(function(){f1.toMethod(o)(x);}, ReferenceError);
|
||||
assertThrows(function(){f2.toMethod(o)(x);}, ReferenceError);
|
||||
assertThrows(function(){f1.toMethod(o)(15);}, ReferenceError);
|
||||
assertThrows(function(){f2.toMethod(o)(15);}, ReferenceError);
|
||||
}());
|
||||
|
Loading…
Reference in New Issue
Block a user