[es6] Support super.property in eval and arrow functions
When we enter a method that needs access to the [[HomeObject]] we allocate a local variable `.home_object` and assign it the value from the [[HomeObject]] private symbol. Something along the lines of: method() { var .home_object = %ThisFunction()[home_object_symbol]; ... } BUG=v8:3867, v8:4031 LOG=N Review URL: https://codereview.chromium.org/1135243004 Cr-Commit-Position: refs/heads/master@{#28644}
This commit is contained in:
parent
2dda8c3d4e
commit
44e9810345
@ -242,6 +242,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ Push(r1);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -307,6 +312,19 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, r0, r1, r2);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
__ Move(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(function()->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, r0, r1, r2);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
@ -1325,27 +1343,6 @@ 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);
|
||||
|
||||
__ mov(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
__ cmp(r0, Operand(isolate()->factory()->undefined_value()));
|
||||
Label done;
|
||||
__ b(ne, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1980,7 +1977,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
const Register scratch = r1;
|
||||
@ -1991,8 +1989,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case KEYED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
@ -2634,7 +2632,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ Push(r0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; r0: home_object
|
||||
Register scratch = r2;
|
||||
Register scratch2 = r3;
|
||||
@ -2650,8 +2649,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ Push(r0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = r2;
|
||||
Register scratch2 = r3;
|
||||
@ -2863,8 +2861,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2876,8 +2873,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2943,8 +2939,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = r1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(r0);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(r0);
|
||||
__ Push(r0);
|
||||
@ -3004,8 +2999,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = r1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(r0);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(r0);
|
||||
__ Push(r0);
|
||||
@ -4847,7 +4841,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
const Register scratch = r1;
|
||||
__ ldr(scratch, MemOperand(sp, kPointerSize));
|
||||
@ -4859,8 +4854,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ Push(result_register());
|
||||
const Register scratch = r1;
|
||||
|
@ -243,6 +243,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ Push(x1);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -307,11 +312,23 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, x0, x1, x2);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Mov(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
__ Mov(LoadDescriptor::SlotRegister(),
|
||||
SmiFromSlot(function()->HomeObjectFeedbackSlot()));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, x0, x1, x2);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
|
||||
|
||||
// Visit the declarations and body unless there is an illegal
|
||||
// redeclaration.
|
||||
if (scope()->HasIllegalRedeclaration()) {
|
||||
@ -1310,28 +1327,6 @@ 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));
|
||||
|
||||
__ Mov(LoadDescriptor::SlotRegister(),
|
||||
SmiFromSlot(expr->HomeObjectFeedbackSlot()));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
__ Mov(x10, Operand(isolate()->factory()->undefined_value()));
|
||||
__ cmp(x0, x10);
|
||||
Label done;
|
||||
__ b(&done, ne);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1951,7 +1946,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
const Register scratch = x10;
|
||||
@ -1961,8 +1957,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case KEYED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
@ -2318,7 +2314,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ Push(x0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; x0: home_object
|
||||
Register scratch = x10;
|
||||
Register scratch2 = x11;
|
||||
@ -2334,8 +2331,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ Push(x0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = x10;
|
||||
Register scratch2 = x11;
|
||||
@ -2550,8 +2546,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2563,8 +2558,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2633,8 +2627,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = x10;
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(x0);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(x0);
|
||||
__ Peek(scratch, kPointerSize);
|
||||
@ -2693,8 +2686,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = x10;
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(x0);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(x0);
|
||||
__ Peek(scratch, kPointerSize);
|
||||
@ -4530,7 +4522,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
const Register scratch = x10;
|
||||
__ Peek(scratch, kPointerSize);
|
||||
@ -4541,8 +4534,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ Push(result_register());
|
||||
const Register scratch1 = x10;
|
||||
|
@ -174,6 +174,7 @@ void AstNumberingVisitor::VisitSuperReference(SuperReference* node) {
|
||||
ReserveFeedbackSlots(node);
|
||||
node->set_base_id(ReserveIdRange(SuperReference::num_ids()));
|
||||
Visit(node->this_var());
|
||||
Visit(node->home_object_var());
|
||||
}
|
||||
|
||||
|
||||
@ -525,6 +526,8 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
|
||||
DisableCrankshaft(kContextAllocatedArguments);
|
||||
}
|
||||
|
||||
ReserveFeedbackSlots(node);
|
||||
|
||||
VisitDeclarations(scope->declarations());
|
||||
if (scope->is_function_scope() && scope->function() != NULL) {
|
||||
// Visit the name of the named function expression.
|
||||
|
@ -248,6 +248,7 @@ class AstValue : public ZoneObject {
|
||||
F(empty, "") \
|
||||
F(eval, "eval") \
|
||||
F(get_template_callsite, "$getTemplateCallSite") \
|
||||
F(home_object, ".home_object") \
|
||||
F(initialize_const_global, "initializeConstGlobal") \
|
||||
F(initialize_var_global, "initializeVarGlobal") \
|
||||
F(is_construct_call, "_IsConstructCall") \
|
||||
|
@ -179,7 +179,7 @@ LanguageMode FunctionLiteral::language_mode() const {
|
||||
|
||||
bool FunctionLiteral::uses_super_property() const {
|
||||
DCHECK_NOT_NULL(scope());
|
||||
return scope()->uses_super_property() || scope()->inner_uses_super_property();
|
||||
return scope()->uses_super_property();
|
||||
}
|
||||
|
||||
|
||||
|
61
src/ast.h
61
src/ast.h
@ -2539,6 +2539,26 @@ class FunctionLiteral final : public Expression {
|
||||
dont_optimize_reason_ = reason;
|
||||
}
|
||||
|
||||
static int num_ids() { return parent_num_ids() + 1; }
|
||||
TypeFeedbackId HomeObjectFeedbackId() { return TypeFeedbackId(local_id(0)); }
|
||||
|
||||
// Type feedback information.
|
||||
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
|
||||
Isolate* isolate, const ICSlotCache* cache) override {
|
||||
return FeedbackVectorRequirements(0, 1);
|
||||
}
|
||||
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
|
||||
ICSlotCache* cache) override {
|
||||
DCHECK(!slot.IsInvalid());
|
||||
home_object_feedback_slot_ = slot;
|
||||
}
|
||||
Code::Kind FeedbackICSlotKind(int index) override { return Code::LOAD_IC; }
|
||||
|
||||
FeedbackVectorICSlot HomeObjectFeedbackSlot() {
|
||||
DCHECK(!home_object_feedback_slot_.IsInvalid());
|
||||
return home_object_feedback_slot_;
|
||||
}
|
||||
|
||||
protected:
|
||||
FunctionLiteral(Zone* zone, const AstRawString* name,
|
||||
AstValueFactory* ast_value_factory, Scope* scope,
|
||||
@ -2560,7 +2580,8 @@ class FunctionLiteral final : public Expression {
|
||||
expected_property_count_(expected_property_count),
|
||||
handler_count_(handler_count),
|
||||
parameter_count_(parameter_count),
|
||||
function_token_position_(RelocInfo::kNoPosition) {
|
||||
function_token_position_(RelocInfo::kNoPosition),
|
||||
home_object_feedback_slot_(FeedbackVectorICSlot::Invalid()) {
|
||||
bitfield_ = IsExpression::encode(function_type != DECLARATION) |
|
||||
IsAnonymous::encode(function_type == ANONYMOUS_EXPRESSION) |
|
||||
Pretenure::encode(false) |
|
||||
@ -2572,6 +2593,8 @@ class FunctionLiteral final : public Expression {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
}
|
||||
|
||||
static int parent_num_ids() { return Expression::num_ids(); }
|
||||
|
||||
private:
|
||||
const AstRawString* raw_name_;
|
||||
Handle<String> name_;
|
||||
@ -2589,6 +2612,9 @@ class FunctionLiteral final : public Expression {
|
||||
int parameter_count_;
|
||||
int function_token_position_;
|
||||
|
||||
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
|
||||
FeedbackVectorICSlot home_object_feedback_slot_;
|
||||
|
||||
unsigned bitfield_;
|
||||
class IsExpression : public BitField<bool, 0, 1> {};
|
||||
class IsAnonymous : public BitField<bool, 1, 1> {};
|
||||
@ -2690,37 +2716,21 @@ class SuperReference final : public Expression {
|
||||
DECLARE_NODE_TYPE(SuperReference)
|
||||
|
||||
VariableProxy* this_var() const { return this_var_; }
|
||||
|
||||
static int num_ids() { return parent_num_ids(); }
|
||||
|
||||
// Type feedback information.
|
||||
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
|
||||
Isolate* isolate, const ICSlotCache* cache) override {
|
||||
return FeedbackVectorRequirements(0, 1);
|
||||
}
|
||||
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
|
||||
ICSlotCache* cache) override {
|
||||
homeobject_feedback_slot_ = slot;
|
||||
}
|
||||
Code::Kind FeedbackICSlotKind(int index) override { return Code::LOAD_IC; }
|
||||
|
||||
FeedbackVectorICSlot HomeObjectFeedbackSlot() {
|
||||
DCHECK(!homeobject_feedback_slot_.IsInvalid());
|
||||
return homeobject_feedback_slot_;
|
||||
}
|
||||
VariableProxy* home_object_var() const { return home_object_var_; }
|
||||
|
||||
protected:
|
||||
SuperReference(Zone* zone, VariableProxy* this_var, int pos)
|
||||
SuperReference(Zone* zone, VariableProxy* this_var,
|
||||
VariableProxy* home_object_var, int pos)
|
||||
: Expression(zone, pos),
|
||||
this_var_(this_var),
|
||||
homeobject_feedback_slot_(FeedbackVectorICSlot::Invalid()) {
|
||||
home_object_var_(home_object_var) {
|
||||
DCHECK(this_var->is_this());
|
||||
DCHECK(home_object_var->raw_name()->IsOneByteEqualTo(".home_object"));
|
||||
}
|
||||
static int parent_num_ids() { return Expression::num_ids(); }
|
||||
|
||||
private:
|
||||
VariableProxy* this_var_;
|
||||
FeedbackVectorICSlot homeobject_feedback_slot_;
|
||||
VariableProxy* home_object_var_;
|
||||
};
|
||||
|
||||
|
||||
@ -3491,8 +3501,9 @@ class AstNodeFactory final BASE_EMBEDDED {
|
||||
return new (zone_) ThisFunction(zone_, pos);
|
||||
}
|
||||
|
||||
SuperReference* NewSuperReference(VariableProxy* this_var, int pos) {
|
||||
return new (zone_) SuperReference(zone_, this_var, pos);
|
||||
SuperReference* NewSuperReference(VariableProxy* this_var,
|
||||
VariableProxy* home_object_var, int pos) {
|
||||
return new (zone_) SuperReference(zone_, this_var, home_object_var, pos);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -2225,6 +2225,13 @@ void AstGraphBuilder::VisitThrow(Throw* expr) {
|
||||
|
||||
|
||||
void AstGraphBuilder::VisitProperty(Property* expr) {
|
||||
if (expr->obj()->IsSuperReference()) {
|
||||
// TODO(turbofan): Implement super here.
|
||||
SetStackOverflow();
|
||||
ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
|
||||
return;
|
||||
}
|
||||
|
||||
Node* value;
|
||||
VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
|
||||
if (expr->key()->IsPropertyName()) {
|
||||
|
@ -676,8 +676,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// accumulator.
|
||||
void EmitKeyedPropertyAssignment(Assignment* expr);
|
||||
|
||||
void EmitLoadHomeObject(SuperReference* expr);
|
||||
|
||||
static bool NeedsHomeObject(Expression* expr) {
|
||||
return FunctionLiteral::NeedsHomeObject(expr);
|
||||
}
|
||||
|
@ -238,6 +238,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ push(edi);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -303,6 +308,19 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, eax, ebx, edx);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ mov(LoadDescriptor::NameRegister(), Immediate(home_object_symbol));
|
||||
__ mov(LoadDescriptor::SlotRegister(),
|
||||
Immediate(SmiFromSlot(function()->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, eax, ebx, edx);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
@ -1251,27 +1269,6 @@ 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);
|
||||
|
||||
__ mov(LoadDescriptor::SlotRegister(),
|
||||
Immediate(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
__ cmp(eax, isolate()->factory()->undefined_value());
|
||||
Label done;
|
||||
__ j(not_equal, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1898,7 +1895,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
__ push(MemOperand(esp, kPointerSize));
|
||||
@ -1916,8 +1914,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case KEYED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
@ -2540,7 +2538,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ push(eax);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; eax: home_object
|
||||
Register scratch = ecx;
|
||||
Register scratch2 = edx;
|
||||
@ -2556,8 +2555,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ push(eax);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = ecx;
|
||||
Register scratch2 = edx;
|
||||
@ -2768,8 +2766,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2781,8 +2778,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2841,8 +2837,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ push(eax);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ push(eax);
|
||||
__ push(eax);
|
||||
@ -2898,8 +2893,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
SetSourcePosition(prop->position());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ push(eax);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ push(eax);
|
||||
__ push(eax);
|
||||
@ -4771,7 +4765,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ push(result_register());
|
||||
__ push(MemOperand(esp, kPointerSize));
|
||||
__ push(result_register());
|
||||
@ -4781,8 +4776,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ push(result_register());
|
||||
__ push(MemOperand(esp, 2 * kPointerSize));
|
||||
|
@ -251,6 +251,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ Push(a1);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -317,6 +322,19 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, v0, a1, a2);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ li(LoadDescriptor::NameRegister(), Operand(home_object_symbol));
|
||||
__ li(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(function()->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, v0, a1, a2);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
@ -1313,26 +1331,6 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ lw(LoadDescriptor::ReceiverRegister(),
|
||||
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ li(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
|
||||
__ li(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
Label done;
|
||||
__ Branch(&done, ne, v0, Operand(isolate()->factory()->undefined_value()));
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1966,7 +1964,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
const Register scratch = a1;
|
||||
@ -1977,7 +1976,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
const Register scratch = a1;
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Move(scratch, result_register());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(scratch, result_register());
|
||||
@ -2610,7 +2610,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ Push(v0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; v0: home_object
|
||||
Register scratch = a2;
|
||||
Register scratch2 = a3;
|
||||
@ -2626,8 +2627,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ Push(v0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = a2;
|
||||
Register scratch2 = a3;
|
||||
@ -2844,8 +2844,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2857,8 +2856,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2921,7 +2919,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = a1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
VisitForAccumulatorValue(super_ref->home_object_var());
|
||||
__ mov(scratch, v0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(scratch, v0, v0, scratch);
|
||||
@ -2979,7 +2977,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = a1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
VisitForAccumulatorValue(super_ref->home_object_var());
|
||||
__ Move(scratch, v0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(scratch, v0, v0, scratch);
|
||||
@ -4851,7 +4849,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
const Register scratch = a1;
|
||||
__ lw(scratch, MemOperand(sp, kPointerSize));
|
||||
@ -4862,7 +4861,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
const Register scratch = a1;
|
||||
const Register scratch1 = t0;
|
||||
__ Move(scratch, result_register());
|
||||
|
@ -248,6 +248,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ Push(a1);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -314,6 +319,19 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, v0, a1, a2);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ li(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
__ li(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(function()->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, v0, a1, a2);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
@ -1310,26 +1328,6 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
|
||||
Comment cnmt(masm_, "[ SuperReference ");
|
||||
|
||||
__ ld(LoadDescriptor::ReceiverRegister(),
|
||||
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ li(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
|
||||
__ li(LoadDescriptor::SlotRegister(),
|
||||
Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
Label done;
|
||||
__ Branch(&done, ne, v0, Operand(isolate()->factory()->undefined_value()));
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1965,7 +1963,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
const Register scratch = a1;
|
||||
@ -1976,7 +1975,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
const Register scratch = a1;
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Move(scratch, result_register());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(scratch, result_register());
|
||||
@ -2609,7 +2609,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ Push(v0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; v0: home_object
|
||||
Register scratch = a2;
|
||||
Register scratch2 = a3;
|
||||
@ -2625,8 +2626,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ Push(v0);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = a2;
|
||||
Register scratch2 = a3;
|
||||
@ -2847,8 +2847,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2860,8 +2859,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2924,7 +2922,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = a1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
VisitForAccumulatorValue(super_ref->home_object_var());
|
||||
__ mov(scratch, v0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(scratch, v0, v0, scratch);
|
||||
@ -2982,7 +2980,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
// Load the function from the receiver.
|
||||
const Register scratch = a1;
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
VisitForAccumulatorValue(super_ref->home_object_var());
|
||||
__ Move(scratch, v0);
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(scratch, v0, v0, scratch);
|
||||
@ -4854,7 +4852,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
const Register scratch = a1;
|
||||
__ ld(scratch, MemOperand(sp, kPointerSize));
|
||||
@ -4865,7 +4864,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
const Register scratch = a1;
|
||||
const Register scratch1 = a4;
|
||||
__ Move(scratch, result_register());
|
||||
|
@ -749,8 +749,13 @@ Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
|
||||
|
||||
Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory,
|
||||
int pos) {
|
||||
// TODO(arv): Split into SuperProperty and SuperCall?
|
||||
VariableProxy* home_object_proxy = scope->NewUnresolved(
|
||||
factory, parser_->ast_value_factory()->home_object_string(),
|
||||
Variable::NORMAL, pos);
|
||||
|
||||
return factory->NewSuperReference(
|
||||
ThisExpression(scope, factory, pos)->AsVariableProxy(),
|
||||
ThisExpression(scope, factory, pos)->AsVariableProxy(), home_object_proxy,
|
||||
pos);
|
||||
}
|
||||
|
||||
@ -1138,7 +1143,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
bool ok = true;
|
||||
|
||||
if (shared_info->is_arrow()) {
|
||||
Scope* scope = NewScope(scope_, ARROW_SCOPE);
|
||||
Scope* scope =
|
||||
NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
|
||||
scope->set_start_position(shared_info->start_position());
|
||||
ExpressionClassifier formals_classifier;
|
||||
bool has_rest = false;
|
||||
|
@ -724,8 +724,7 @@ class ParserTraits {
|
||||
|
||||
Expression* ThisExpression(Scope* scope, AstNodeFactory* factory,
|
||||
int pos = RelocInfo::kNoPosition);
|
||||
Expression* SuperReference(Scope* scope, AstNodeFactory* factory,
|
||||
int pos = RelocInfo::kNoPosition);
|
||||
Expression* SuperReference(Scope* scope, AstNodeFactory* factory, int pos);
|
||||
Expression* DefaultConstructor(bool call_super, Scope* scope, int pos,
|
||||
int end_pos);
|
||||
Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
|
||||
|
@ -110,7 +110,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
||||
FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction,
|
||||
&top_factory);
|
||||
scope_->SetLanguageMode(language_mode);
|
||||
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE);
|
||||
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
|
||||
PreParserFactory function_factory(NULL);
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
||||
&function_factory);
|
||||
@ -1028,7 +1028,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
|
||||
// Parse function body.
|
||||
bool outer_is_script_scope = scope_->is_script_scope();
|
||||
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE);
|
||||
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
|
||||
PreParserFactory factory(NULL);
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
||||
&factory);
|
||||
|
@ -339,12 +339,17 @@ class ParserBase : public Traits {
|
||||
Mode old_mode_;
|
||||
};
|
||||
|
||||
Scope* NewScope(Scope* parent, ScopeType scope_type,
|
||||
FunctionKind kind = kNormalFunction) {
|
||||
Scope* NewScope(Scope* parent, ScopeType scope_type) {
|
||||
// Must always pass the function kind for FUNCTION_SCOPE and ARROW_SCOPE.
|
||||
DCHECK(scope_type != FUNCTION_SCOPE);
|
||||
DCHECK(scope_type != ARROW_SCOPE);
|
||||
return NewScope(parent, scope_type, kNormalFunction);
|
||||
}
|
||||
|
||||
Scope* NewScope(Scope* parent, ScopeType scope_type, FunctionKind kind) {
|
||||
DCHECK(ast_value_factory());
|
||||
DCHECK(scope_type != MODULE_SCOPE || allow_harmony_modules());
|
||||
DCHECK((scope_type == FUNCTION_SCOPE && IsValidFunctionKind(kind)) ||
|
||||
kind == kNormalFunction);
|
||||
DCHECK(scope_type != ARROW_SCOPE || IsArrowFunction(kind));
|
||||
Scope* result = new (zone())
|
||||
Scope(zone(), parent, scope_type, ast_value_factory(), kind);
|
||||
result->Initialize();
|
||||
@ -1711,7 +1716,8 @@ class PreParserTraits {
|
||||
}
|
||||
|
||||
static PreParserExpression SuperReference(Scope* scope,
|
||||
PreParserFactory* factory) {
|
||||
PreParserFactory* factory,
|
||||
int pos) {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
|
||||
@ -2393,7 +2399,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
MessageTemplate::kUnexpectedToken,
|
||||
Token::String(Token::RPAREN));
|
||||
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||
Scope* scope =
|
||||
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
|
||||
scope->set_start_position(beg_pos);
|
||||
ExpressionClassifier args_classifier;
|
||||
bool has_rest = false;
|
||||
@ -2920,7 +2927,8 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
CHECK_OK);
|
||||
Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
|
||||
bool has_rest = false;
|
||||
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||
Scope* scope =
|
||||
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
|
||||
scope->set_start_position(lhs_location.beg_pos);
|
||||
Scanner::Location duplicate_loc = Scanner::Location::invalid();
|
||||
this->ParseArrowFunctionFormalParameters(scope, expression, loc, &has_rest,
|
||||
@ -3507,7 +3515,7 @@ ParserBase<Traits>::ParseStrongSuperCallExpression(
|
||||
Consume(Token::SUPER);
|
||||
int pos = position();
|
||||
Scanner::Location super_loc = scanner()->location();
|
||||
ExpressionT expr = this->SuperReference(scope_, factory());
|
||||
ExpressionT expr = this->SuperReference(scope_, factory(), pos);
|
||||
|
||||
if (peek() != Token::LPAREN) {
|
||||
ReportMessage(MessageTemplate::kStrongConstructorSuper);
|
||||
@ -3556,21 +3564,23 @@ typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseSuperExpression(bool is_new,
|
||||
ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
int pos = position();
|
||||
Expect(Token::SUPER, CHECK_OK);
|
||||
|
||||
// TODO(wingo): Does this actually work with lazily compiled arrows?
|
||||
FunctionState* function_state = function_state_;
|
||||
while (IsArrowFunction(function_state->kind())) {
|
||||
function_state = function_state->outer();
|
||||
}
|
||||
// TODO(arv): Handle eval scopes similarly.
|
||||
Scope* scope = scope_->DeclarationScope();
|
||||
|
||||
FunctionKind kind = function_state->kind();
|
||||
while (scope->is_eval_scope() || scope->is_arrow_scope()) {
|
||||
scope = scope->outer_scope();
|
||||
DCHECK_NOT_NULL(scope);
|
||||
scope = scope->DeclarationScope();
|
||||
}
|
||||
|
||||
FunctionKind kind = scope->function_kind();
|
||||
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
|
||||
i::IsConstructor(kind)) {
|
||||
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
|
||||
scope_->RecordSuperPropertyUsage();
|
||||
return this->SuperReference(scope_, factory());
|
||||
scope->RecordSuperPropertyUsage();
|
||||
return this->SuperReference(scope_, factory(), pos);
|
||||
}
|
||||
// new super() is never allowed.
|
||||
// super() is only allowed in derived constructor
|
||||
@ -3582,8 +3592,10 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new,
|
||||
*ok = false;
|
||||
return this->EmptyExpression();
|
||||
}
|
||||
function_state->set_super_location(scanner()->location());
|
||||
return this->SuperReference(scope_, factory());
|
||||
// TODO(rossberg): This might not be the correct FunctionState for the
|
||||
// method here.
|
||||
function_state_->set_super_location(scanner()->location());
|
||||
return this->SuperReference(scope_, factory(), pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,12 +154,13 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
||||
function_kind_ = function_kind;
|
||||
block_scope_is_class_scope_ = false;
|
||||
scope_name_ = ast_value_factory_->empty_string();
|
||||
dynamics_ = NULL;
|
||||
receiver_ = NULL;
|
||||
dynamics_ = nullptr;
|
||||
receiver_ = nullptr;
|
||||
new_target_ = nullptr;
|
||||
function_ = NULL;
|
||||
arguments_ = NULL;
|
||||
illegal_redecl_ = NULL;
|
||||
function_ = nullptr;
|
||||
arguments_ = nullptr;
|
||||
home_object_ = nullptr;
|
||||
illegal_redecl_ = nullptr;
|
||||
scope_inside_with_ = false;
|
||||
scope_contains_with_ = false;
|
||||
scope_calls_eval_ = false;
|
||||
@ -172,7 +173,6 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
||||
outer_scope_calls_sloppy_eval_ = false;
|
||||
inner_scope_calls_eval_ = false;
|
||||
inner_scope_uses_arguments_ = false;
|
||||
inner_scope_uses_super_property_ = false;
|
||||
force_eager_compilation_ = false;
|
||||
force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
|
||||
? outer_scope->has_forced_context_allocation() : false;
|
||||
@ -337,6 +337,17 @@ void Scope::Initialize() {
|
||||
Variable::ARGUMENTS,
|
||||
kCreatedInitialized);
|
||||
}
|
||||
|
||||
if (is_function_scope() &&
|
||||
(IsConciseMethod(function_kind_) || IsConstructor(function_kind_) ||
|
||||
IsAccessorFunction(function_kind_))) {
|
||||
DCHECK(!is_arrow_scope());
|
||||
// Declare '.home_object' variable which exists in all methods.
|
||||
// Note that it might never be accessed, in which case it won't be
|
||||
// allocated during variable allocation.
|
||||
variables_.Declare(this, ast_value_factory_->home_object_string(), VAR,
|
||||
Variable::NORMAL, kCreatedInitialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -929,8 +940,6 @@ void Scope::Print(int n) {
|
||||
if (inner_scope_uses_arguments_) {
|
||||
Indent(n1, "// inner scope uses 'arguments'\n");
|
||||
}
|
||||
if (inner_scope_uses_super_property_)
|
||||
Indent(n1, "// inner scope uses 'super' property\n");
|
||||
if (outer_scope_calls_sloppy_eval_) {
|
||||
Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
|
||||
}
|
||||
@ -1287,10 +1296,6 @@ void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
|
||||
if (inner->scope_uses_arguments_ || inner->inner_scope_uses_arguments_) {
|
||||
inner_scope_uses_arguments_ = true;
|
||||
}
|
||||
if (inner->scope_uses_super_property_ ||
|
||||
inner->inner_scope_uses_super_property_) {
|
||||
inner_scope_uses_super_property_ = true;
|
||||
}
|
||||
}
|
||||
if (inner->force_eager_compilation_) {
|
||||
force_eager_compilation_ = true;
|
||||
@ -1398,6 +1403,18 @@ void Scope::AllocateParameterLocals(Isolate* isolate) {
|
||||
rest_parameter_ = NULL;
|
||||
}
|
||||
|
||||
Variable* home_object_var =
|
||||
LookupLocal(ast_value_factory_->home_object_string());
|
||||
if (home_object_var != nullptr && uses_super_property() &&
|
||||
MustAllocate(home_object_var)) {
|
||||
// TODO(arv): super() uses a SuperReference so it generates a VariableProxy
|
||||
// for the .home_object which makes it look like we need to allocate the
|
||||
// home_object_var.
|
||||
// Consider splitting the AST node into 2 different nodes since the
|
||||
// semantics is just so different.
|
||||
home_object_ = home_object_var;
|
||||
}
|
||||
|
||||
// The same parameter may occur multiple times in the parameters_ list.
|
||||
// If it does, and if it is not copied into the context object, it must
|
||||
// receive the highest parameter index for that parameter; thus iteration
|
||||
|
12
src/scopes.h
12
src/scopes.h
@ -409,6 +409,16 @@ class Scope: public ZoneObject {
|
||||
return arguments_;
|
||||
}
|
||||
|
||||
// A local variable to the [[HomeObject]] used by methods if we need to
|
||||
// allocate it; NULL otherwise.
|
||||
Variable* home_object_var() const {
|
||||
DCHECK(home_object_ == nullptr ||
|
||||
(is_function_scope() && (IsConciseMethod(function_kind()) ||
|
||||
IsAccessorFunction(function_kind()) ||
|
||||
IsConstructor(function_kind()))));
|
||||
return home_object_;
|
||||
}
|
||||
|
||||
// Declarations list.
|
||||
ZoneList<Declaration*>* declarations() { return &decls_; }
|
||||
|
||||
@ -567,6 +577,8 @@ class Scope: public ZoneObject {
|
||||
Variable* new_target_;
|
||||
// Convenience variable; function scopes only.
|
||||
Variable* arguments_;
|
||||
// Convenience variable; method scopes only.
|
||||
Variable* home_object_;
|
||||
// Module descriptor; module scopes only.
|
||||
ModuleDescriptor* module_descriptor_;
|
||||
|
||||
|
@ -234,6 +234,11 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
}
|
||||
|
||||
Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
__ Push(rdi);
|
||||
}
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
@ -301,6 +306,20 @@ void FullCodeGenerator::Generate() {
|
||||
SetVar(arguments, rax, rbx, rdx);
|
||||
}
|
||||
|
||||
// Possibly set up a local binding to the [[HomeObject]].
|
||||
// Variable* home_object_var = scope()->home_object_var();
|
||||
if (home_object_var != nullptr) {
|
||||
Comment cmnt(masm_, "[ Home object");
|
||||
__ Pop(LoadDescriptor::ReceiverRegister());
|
||||
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
|
||||
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
|
||||
__ Move(LoadDescriptor::SlotRegister(),
|
||||
SmiFromSlot(function()->HomeObjectFeedbackSlot()));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
SetVar(home_object_var, rax, rbx, rdx);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
__ CallRuntime(Runtime::kTraceEnter, 0);
|
||||
}
|
||||
@ -1285,27 +1304,6 @@ 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);
|
||||
|
||||
__ Move(LoadDescriptor::SlotRegister(),
|
||||
SmiFromSlot(expr->HomeObjectFeedbackSlot()));
|
||||
CallLoadIC(NOT_CONTEXTUAL);
|
||||
|
||||
__ Cmp(rax, isolate()->factory()->undefined_value());
|
||||
Label done;
|
||||
__ j(not_equal, &done);
|
||||
__ CallRuntime(Runtime::kThrowNonMethodError, 0);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
|
||||
int offset) {
|
||||
if (NeedsHomeObject(initializer)) {
|
||||
@ -1939,7 +1937,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case NAMED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
__ Push(MemOperand(rsp, kPointerSize));
|
||||
@ -1948,8 +1947,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
case KEYED_SUPER_PROPERTY:
|
||||
VisitForStackValue(property->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(property->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(
|
||||
property->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(property->key());
|
||||
__ Push(result_register());
|
||||
if (expr->is_compound()) {
|
||||
@ -2540,7 +2539,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
__ Push(rax);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
// stack: value, this; rax: home_object
|
||||
Register scratch = rcx;
|
||||
Register scratch2 = rdx;
|
||||
@ -2556,8 +2556,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
__ Push(rax);
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
Register scratch = rcx;
|
||||
Register scratch2 = rdx;
|
||||
@ -2765,8 +2764,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitNamedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
EmitNamedSuperPropertyLoad(expr);
|
||||
}
|
||||
} else {
|
||||
@ -2778,8 +2776,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
||||
EmitKeyedPropertyLoad(expr);
|
||||
} else {
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(expr->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(expr->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForStackValue(expr->key());
|
||||
EmitKeyedSuperPropertyLoad(expr);
|
||||
}
|
||||
@ -2838,8 +2835,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
|
||||
DCHECK(!key->value()->IsSmi());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(rax);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(rax);
|
||||
__ Push(rax);
|
||||
@ -2896,8 +2892,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
|
||||
SetSourcePosition(prop->position());
|
||||
// Load the function from the receiver.
|
||||
SuperReference* super_ref = prop->obj()->AsSuperReference();
|
||||
EmitLoadHomeObject(super_ref);
|
||||
__ Push(rax);
|
||||
VisitForStackValue(super_ref->home_object_var());
|
||||
VisitForAccumulatorValue(super_ref->this_var());
|
||||
__ Push(rax);
|
||||
__ Push(rax);
|
||||
@ -4791,7 +4786,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case NAMED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
VisitForAccumulatorValue(
|
||||
prop->obj()->AsSuperReference()->home_object_var());
|
||||
__ Push(result_register());
|
||||
__ Push(MemOperand(rsp, kPointerSize));
|
||||
__ Push(result_register());
|
||||
@ -4801,8 +4797,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
case KEYED_SUPER_PROPERTY: {
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
|
||||
EmitLoadHomeObject(prop->obj()->AsSuperReference());
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(prop->obj()->AsSuperReference()->home_object_var());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ Push(result_register());
|
||||
__ Push(MemOperand(rsp, 2 * kPointerSize));
|
||||
|
@ -310,10 +310,10 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
|
||||
|
||||
// Verify that we gathered feedback.
|
||||
int expected_slots = 0;
|
||||
int expected_ic_slots = 1;
|
||||
int expected_ic_slots = 2;
|
||||
CHECK_EQ(expected_slots, feedback_vector->Slots());
|
||||
CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
|
||||
FeedbackVectorICSlot slot_for_a(0);
|
||||
FeedbackVectorICSlot slot_for_a(1);
|
||||
Object* object = feedback_vector->Get(slot_for_a);
|
||||
CHECK(object->IsWeakCell() &&
|
||||
WeakCell::cast(object)->value()->IsJSFunction());
|
||||
@ -362,7 +362,7 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) {
|
||||
// Now a feedback vector is allocated.
|
||||
CHECK(f->shared()->is_compiled());
|
||||
int expected_slots = 0;
|
||||
int expected_ic_slots = 2;
|
||||
int expected_ic_slots = 3;
|
||||
CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
|
||||
CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ TEST(VectorICProfilerStatistics) {
|
||||
CHECK_EQ(0, feedback_info->ic_generic_count());
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
handle(f->shared()->feedback_vector(), isolate);
|
||||
int ic_slot = 0;
|
||||
int ic_slot = 1;
|
||||
CallICNexus nexus(feedback_vector, FeedbackVectorICSlot(ic_slot));
|
||||
CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
|
||||
CHECK_EQ(0, feedback_vector->ic_generic_count());
|
||||
@ -222,7 +222,7 @@ TEST(VectorCallICStates) {
|
||||
// There should be one IC.
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
|
||||
FeedbackVectorICSlot slot(0);
|
||||
FeedbackVectorICSlot slot(1);
|
||||
CallICNexus nexus(feedback_vector, slot);
|
||||
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
|
||||
// CallIC doesn't return map feedback.
|
||||
@ -264,7 +264,7 @@ TEST(VectorLoadICStates) {
|
||||
// There should be one IC.
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
|
||||
FeedbackVectorICSlot slot(0);
|
||||
FeedbackVectorICSlot slot(1);
|
||||
LoadICNexus nexus(feedback_vector, slot);
|
||||
CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
|
||||
|
||||
@ -322,8 +322,8 @@ TEST(VectorLoadICSlotSharing) {
|
||||
// There should be one IC slot.
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
|
||||
CHECK_EQ(1, feedback_vector->ICSlots());
|
||||
FeedbackVectorICSlot slot(0);
|
||||
CHECK_EQ(2, feedback_vector->ICSlots());
|
||||
FeedbackVectorICSlot slot(1);
|
||||
LoadICNexus nexus(feedback_vector, slot);
|
||||
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
|
||||
}
|
||||
@ -346,7 +346,7 @@ TEST(VectorLoadICOnSmi) {
|
||||
// There should be one IC.
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
|
||||
FeedbackVectorICSlot slot(0);
|
||||
FeedbackVectorICSlot slot(1);
|
||||
LoadICNexus nexus(feedback_vector, slot);
|
||||
CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
|
||||
|
||||
|
@ -3322,10 +3322,10 @@ TEST(IncrementalMarkingPreservesMonomorphicCallIC) {
|
||||
|
||||
Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
|
||||
|
||||
int expected_slots = 2;
|
||||
int expected_slots = 3;
|
||||
CHECK_EQ(expected_slots, feedback_vector->ICSlots());
|
||||
int slot1 = 0;
|
||||
int slot2 = 1;
|
||||
int slot1 = 1;
|
||||
int slot2 = 2;
|
||||
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsWeakCell());
|
||||
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsWeakCell());
|
||||
|
||||
@ -3448,14 +3448,14 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) {
|
||||
CcTest::global()->Get(v8_str("f"))));
|
||||
|
||||
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, MONOMORPHIC);
|
||||
CheckVectorIC(f, 1, MONOMORPHIC);
|
||||
CHECK(ic_before->ic_state() == DEFAULT);
|
||||
|
||||
SimulateIncrementalMarking(CcTest::heap());
|
||||
CcTest::heap()->CollectAllGarbage();
|
||||
|
||||
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, MONOMORPHIC);
|
||||
CheckVectorIC(f, 1, MONOMORPHIC);
|
||||
CHECK(ic_after->ic_state() == DEFAULT);
|
||||
}
|
||||
|
||||
@ -3480,7 +3480,7 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
|
||||
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
|
||||
|
||||
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, MONOMORPHIC);
|
||||
CheckVectorIC(f, 1, MONOMORPHIC);
|
||||
CHECK(ic_before->ic_state() == DEFAULT);
|
||||
|
||||
// Fire context dispose notification.
|
||||
@ -3489,7 +3489,7 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
|
||||
CcTest::heap()->CollectAllGarbage();
|
||||
|
||||
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorICCleared(f, 0);
|
||||
CheckVectorICCleared(f, 1);
|
||||
CHECK(ic_after->ic_state() == DEFAULT);
|
||||
}
|
||||
|
||||
@ -3521,7 +3521,7 @@ TEST(IncrementalMarkingPreservesPolymorphicIC) {
|
||||
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
|
||||
|
||||
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, POLYMORPHIC);
|
||||
CheckVectorIC(f, 1, POLYMORPHIC);
|
||||
CHECK(ic_before->ic_state() == DEFAULT);
|
||||
|
||||
// Fire context dispose notification.
|
||||
@ -3529,7 +3529,7 @@ TEST(IncrementalMarkingPreservesPolymorphicIC) {
|
||||
CcTest::heap()->CollectAllGarbage();
|
||||
|
||||
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, POLYMORPHIC);
|
||||
CheckVectorIC(f, 1, POLYMORPHIC);
|
||||
CHECK(ic_after->ic_state() == DEFAULT);
|
||||
}
|
||||
|
||||
@ -3561,7 +3561,7 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
|
||||
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
|
||||
|
||||
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CheckVectorIC(f, 0, POLYMORPHIC);
|
||||
CheckVectorIC(f, 1, POLYMORPHIC);
|
||||
CHECK(ic_before->ic_state() == DEFAULT);
|
||||
|
||||
// Fire context dispose notification.
|
||||
@ -3569,7 +3569,7 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
|
||||
SimulateIncrementalMarking(CcTest::heap());
|
||||
CcTest::heap()->CollectAllGarbage();
|
||||
|
||||
CheckVectorICCleared(f, 0);
|
||||
CheckVectorICCleared(f, 1);
|
||||
CHECK(ic_before->ic_state() == DEFAULT);
|
||||
}
|
||||
|
||||
@ -4719,12 +4719,12 @@ TEST(MonomorphicStaysMonomorphicAfterGC) {
|
||||
CompileRun("(testIC())");
|
||||
}
|
||||
heap->CollectAllGarbage();
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, MONOMORPHIC);
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 1, MONOMORPHIC);
|
||||
{
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
CompileRun("(testIC())");
|
||||
}
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, MONOMORPHIC);
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 1, MONOMORPHIC);
|
||||
}
|
||||
|
||||
|
||||
@ -4755,12 +4755,12 @@ TEST(PolymorphicStaysPolymorphicAfterGC) {
|
||||
CompileRun("(testIC())");
|
||||
}
|
||||
heap->CollectAllGarbage();
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC);
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 1, POLYMORPHIC);
|
||||
{
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
CompileRun("(testIC())");
|
||||
}
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC);
|
||||
CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 1, POLYMORPHIC);
|
||||
}
|
||||
|
||||
|
||||
|
@ -976,9 +976,9 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
||||
SUPER_PROPERTY = 1 << 1,
|
||||
THIS = 1 << 2,
|
||||
INNER_ARGUMENTS = 1 << 3,
|
||||
INNER_SUPER_PROPERTY = 1 << 4,
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static const struct {
|
||||
const char* body;
|
||||
int expected;
|
||||
@ -992,7 +992,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
||||
{"return this + arguments[0] + super.x",
|
||||
ARGUMENTS | SUPER_PROPERTY | THIS},
|
||||
{"return x => this + x", THIS},
|
||||
{"return x => super.f() + x", INNER_SUPER_PROPERTY},
|
||||
{"return x => super.f() + x", SUPER_PROPERTY},
|
||||
{"this.foo = 42;", THIS},
|
||||
{"this.foo();", THIS},
|
||||
{"if (foo()) { this.f() }", THIS},
|
||||
@ -1018,15 +1018,15 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
||||
{"\"use strict\"; while (true) { let x; this, arguments; }",
|
||||
INNER_ARGUMENTS | THIS},
|
||||
{"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
|
||||
INNER_ARGUMENTS | INNER_SUPER_PROPERTY | THIS},
|
||||
INNER_ARGUMENTS | SUPER_PROPERTY | THIS},
|
||||
{"\"use strict\"; if (foo()) { let x; this.f() }", THIS},
|
||||
{"\"use strict\"; if (foo()) { let x; super.f() }",
|
||||
INNER_SUPER_PROPERTY},
|
||||
{"\"use strict\"; if (foo()) { let x; super.f() }", SUPER_PROPERTY},
|
||||
{"\"use strict\"; if (1) {"
|
||||
" let x; return { m() { return this + super.m() + arguments } }"
|
||||
"}",
|
||||
NONE},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
i::Isolate* isolate = CcTest::i_isolate();
|
||||
i::Factory* factory = isolate->factory();
|
||||
@ -1042,7 +1042,6 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
||||
for (unsigned i = 0; i < arraysize(source_data); ++i) {
|
||||
// Super property is only allowed in constructor and method.
|
||||
if (((source_data[i].expected & SUPER_PROPERTY) ||
|
||||
(source_data[i].expected & INNER_SUPER_PROPERTY) ||
|
||||
(source_data[i].expected == NONE)) && j != 2) {
|
||||
continue;
|
||||
}
|
||||
@ -1090,8 +1089,6 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
||||
}
|
||||
CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
|
||||
scope->inner_uses_arguments());
|
||||
CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
|
||||
scope->inner_uses_super_property());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-classes --allow-natives-syntax
|
||||
// Flags: --harmony-classes --harmony-arrow-functions --allow-natives-syntax
|
||||
|
||||
|
||||
(function TestHomeObject() {
|
||||
@ -131,3 +131,42 @@
|
||||
|
||||
assertEquals(42, o.g().next().value);
|
||||
})();
|
||||
|
||||
|
||||
(function TestSuperPropertyInEval() {
|
||||
var y = 3;
|
||||
var p = {
|
||||
m() { return 1; },
|
||||
get x() { return 2; }
|
||||
};
|
||||
var o = {
|
||||
__proto__: p,
|
||||
eval() {
|
||||
assertSame(super.x, eval('super.x'));
|
||||
assertSame(super.m(), eval('super.m()'));
|
||||
// Global eval.
|
||||
assertThrows('super.x', SyntaxError);
|
||||
assertThrows('super.m()', SyntaxError);
|
||||
return eval('super.m()');
|
||||
}
|
||||
};
|
||||
assertSame(1, o.eval());
|
||||
})();
|
||||
|
||||
|
||||
(function TestSuperPropertyInArrow() {
|
||||
var y = 3;
|
||||
var p = {
|
||||
m() { return 1; },
|
||||
get x() { return 2; }
|
||||
};
|
||||
var o = {
|
||||
__proto__: p,
|
||||
arrow() {
|
||||
assertSame(super.x, (() => super.x)());
|
||||
assertSame(super.m(), (() => super.m())());
|
||||
return (() => super.m())();
|
||||
}
|
||||
};
|
||||
assertSame(1, o.arrow());
|
||||
})();
|
||||
|
@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-classes --allow-natives-syntax
|
||||
// Flags: --harmony-classes --harmony-arrow-functions --allow-natives-syntax
|
||||
|
||||
|
||||
(function TestSuperNamedLoads() {
|
||||
function Base() { }
|
||||
@ -2053,6 +2054,7 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44);
|
||||
assertInstanceof(f, Number);
|
||||
}());
|
||||
|
||||
|
||||
(function TestSuperCallErrorCases() {
|
||||
'use strict';
|
||||
class T extends Object {
|
||||
@ -2064,3 +2066,44 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44);
|
||||
T.__proto__ = null;
|
||||
assertThrows(function() { new T(); }, TypeError);
|
||||
}());
|
||||
|
||||
|
||||
(function TestSuperPropertyInEval() {
|
||||
'use strict';
|
||||
let y = 3;
|
||||
class Base {
|
||||
m() { return 1; }
|
||||
get x() { return 2; }
|
||||
}
|
||||
class Derived extends Base {
|
||||
eval() {
|
||||
assertSame(super.x, eval('super.x'));
|
||||
assertSame(super.m(), eval('super.m()'));
|
||||
// Global eval.
|
||||
assertThrows('super.x', SyntaxError);
|
||||
assertThrows('super.m()', SyntaxError);
|
||||
return eval('super.m()');
|
||||
}
|
||||
}
|
||||
let d = new Derived();
|
||||
assertSame(1, d.eval());
|
||||
})();
|
||||
|
||||
|
||||
(function TestSuperPropertyInArrow() {
|
||||
'use strict';
|
||||
let y = 3;
|
||||
class Base {
|
||||
m() { return 1; }
|
||||
get x() { return 2; }
|
||||
}
|
||||
class Derived extends Base {
|
||||
arrow() {
|
||||
assertSame(super.x, (() => super.x)());
|
||||
assertSame(super.m(), (() => super.m())());
|
||||
return (() => super.m())();
|
||||
}
|
||||
}
|
||||
let d = new Derived();
|
||||
assertSame(1, d.arrow());
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user