From: dslomov@chromium.org Date: Fri, 19 Sep 2014 11:08:04 +0000 (+0000) Subject: Implement loads and calls from 'super' X-Git-Tag: upstream/4.7.83~6812 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e36aacdee21be8973447e39f7084a1ffb366168d;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index c3ab771..6108c0b 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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 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 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); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 4611363..1928aa5 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -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 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. diff --git a/src/compiler.cc b/src/compiler.cc index 644f7e9..8653d81 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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()); diff --git a/src/full-codegen.cc b/src/full-codegen.cc index dd7558e..35d51d9 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -833,8 +833,7 @@ void FullCodeGenerator::SetStatementPosition(Statement* stmt) { void FullCodeGenerator::VisitSuperReference(SuperReference* super) { - DCHECK(FLAG_harmony_classes); - UNIMPLEMENTED(); + __ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0); } diff --git a/src/full-codegen.h b/src/full-codegen.h index 605380f..71e1b60 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -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, TypeFeedbackId id = TypeFeedbackId::None()); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 9e025f7..345cce3 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index e95c795..a5065aa 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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 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 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. diff --git a/src/messages.js b/src/messages.js index 2fd5b38..d4375ef 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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"], diff --git a/src/runtime.cc b/src/runtime.cc index 530deba..743086f 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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 proto = PrototypeIterator::GetCurrent(iter); + if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); + + LookupIterator it(receiver, name, Handle::cast(proto)); + Handle 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(NULL, 0))); +} + + +RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) { + HandleScope scope(isolate); + DCHECK(args.length() == 0); + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, + NewReferenceError("unsupported_super", HandleVector(NULL, 0))); +} + + RUNTIME_FUNCTION(Runtime_ThrowNotDateError) { HandleScope scope(isolate); DCHECK(args.length() == 0); diff --git a/src/runtime.h b/src/runtime.h index 603745e..38e1469 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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) \ diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index c789f26..1c7f095 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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 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 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); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 51ad973..8fd8743 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -9543,18 +9543,14 @@ TEST(AccessControlES5) { } -static bool GetOwnPropertyNamesNamedBlocker(Local global, - Local name, - v8::AccessType type, - Local data) { +static bool BlockEverythingNamed(Local object, Local name, + v8::AccessType type, Local data) { return false; } -static bool GetOwnPropertyNamesIndexedBlocker(Local global, - uint32_t key, - v8::AccessType type, - Local data) { +static bool BlockEverythingIndexed(Local object, uint32_t key, + v8::AccessType type, Local 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 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 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& info) { v8::Handle result = v8::Array::New(info.GetIsolate(), 2); diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js new file mode 100644 index 0000000..89fb4b1 --- /dev/null +++ b/test/mjsunit/harmony/super.js @@ -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()); +}()); +*/ diff --git a/test/mjsunit/runtime-gen/loadfromsuper.js b/test/mjsunit/runtime-gen/loadfromsuper.js new file mode 100644 index 0000000..25f4ff9 --- /dev/null +++ b/test/mjsunit/runtime-gen/loadfromsuper.js @@ -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);