Skip to content

Commit 06a792b

Browse files
wingoCommit bot
authored andcommitted
Resolve references to "this" the same way as normal variables
Make the parser handle references to "this" as unresolved variables, so the same logic as for the rest of function parameters is used for the receiver. Minor additions to the code generation handle copying the receiver to the context, along with the rest of the function parameters. Based on work by Adrian Perez de Castro <aperez@igalia.com>. BUG=v8:2700 LOG=N Review URL: https://codereview.chromium.org/1130733003 Cr-Commit-Position: refs/heads/master@{#28263}
1 parent fe0e49d commit 06a792b

26 files changed

Lines changed: 313 additions & 120 deletions

src/arm/full-codegen-arm.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ void FullCodeGenerator::Generate() {
127127
// global proxy when called as functions (without an explicit receiver
128128
// object).
129129
if (is_sloppy(info->language_mode()) && !info->is_native() &&
130-
info->MayUseThis()) {
130+
info->MayUseThis() && info->scope()->has_this_declaration()) {
131131
Label ok;
132132
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
133133
__ ldr(r2, MemOperand(sp, receiver_offset));
@@ -216,8 +216,9 @@ void FullCodeGenerator::Generate() {
216216
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
217217
// Copy any necessary parameters into the context.
218218
int num_parameters = info->scope()->num_parameters();
219-
for (int i = 0; i < num_parameters; i++) {
220-
Variable* var = scope()->parameter(i);
219+
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
220+
for (int i = first_parameter; i < num_parameters; i++) {
221+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
221222
if (var->IsContextSlot()) {
222223
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
223224
(num_parameters - 1 - i) * kPointerSize;
@@ -3066,8 +3067,9 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
30663067
__ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
30673068

30683069
// r3: the receiver of the enclosing function.
3069-
int receiver_offset = 2 + info_->scope()->num_parameters();
3070-
__ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize));
3070+
Variable* this_var = scope()->LookupThis();
3071+
DCHECK_NOT_NULL(this_var);
3072+
__ ldr(r3, VarOperand(this_var, r3));
30713073

30723074
// r2: language mode.
30733075
__ mov(r2, Operand(Smi::FromInt(language_mode())));

src/arm/lithium-codegen-arm.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ bool LCodeGen::GeneratePrologue() {
121121
// global proxy when called as functions (without an explicit receiver
122122
// object).
123123
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
124-
!info_->is_native()) {
124+
!info_->is_native() && info_->scope()->has_this_declaration()) {
125125
Label ok;
126126
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
127127
__ ldr(r2, MemOperand(sp, receiver_offset));
@@ -197,8 +197,9 @@ bool LCodeGen::GeneratePrologue() {
197197
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
198198
// Copy any necessary parameters into the context.
199199
int num_parameters = scope()->num_parameters();
200-
for (int i = 0; i < num_parameters; i++) {
201-
Variable* var = scope()->parameter(i);
200+
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
201+
for (int i = first_parameter; i < num_parameters; i++) {
202+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
202203
if (var->IsContextSlot()) {
203204
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
204205
(num_parameters - 1 - i) * kPointerSize;

src/arm64/full-codegen-arm64.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ void FullCodeGenerator::Generate() {
125125
// global proxy when called as functions (without an explicit receiver
126126
// object).
127127
if (is_sloppy(info->language_mode()) && !info->is_native() &&
128-
info->MayUseThis()) {
128+
info->MayUseThis() && info->scope()->has_this_declaration()) {
129129
Label ok;
130130
int receiver_offset = info->scope()->num_parameters() * kXRegSize;
131131
__ Peek(x10, receiver_offset);
@@ -217,8 +217,9 @@ void FullCodeGenerator::Generate() {
217217
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
218218
// Copy any necessary parameters into the context.
219219
int num_parameters = info->scope()->num_parameters();
220-
for (int i = 0; i < num_parameters; i++) {
221-
Variable* var = scope()->parameter(i);
220+
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
221+
for (int i = first_parameter; i < num_parameters; i++) {
222+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
222223
if (var->IsContextSlot()) {
223224
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
224225
(num_parameters - 1 - i) * kPointerSize;
@@ -2751,8 +2752,9 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
27512752

27522753
__ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
27532754
// Prepare to push the receiver of the enclosing function.
2754-
int receiver_offset = 2 + info_->scope()->num_parameters();
2755-
__ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize));
2755+
Variable* this_var = scope()->LookupThis();
2756+
DCHECK_NOT_NULL(this_var);
2757+
__ Ldr(x11, VarOperand(this_var, x11));
27562758

27572759
// Prepare to push the language mode.
27582760
__ Mov(x12, Smi::FromInt(language_mode()));

src/arm64/lithium-codegen-arm64.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ bool LCodeGen::GeneratePrologue() {
669669
// global proxy when called as functions (without an explicit receiver
670670
// object).
671671
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
672-
!info_->is_native()) {
672+
!info()->is_native() && info()->scope()->has_this_declaration()) {
673673
Label ok;
674674
int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
675675
__ Peek(x10, receiver_offset);
@@ -728,8 +728,9 @@ bool LCodeGen::GeneratePrologue() {
728728
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
729729
// Copy any necessary parameters into the context.
730730
int num_parameters = scope()->num_parameters();
731-
for (int i = 0; i < num_parameters; i++) {
732-
Variable* var = scope()->parameter(i);
731+
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
732+
for (int i = first_parameter; i < num_parameters; i++) {
733+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
733734
if (var->IsContextSlot()) {
734735
Register value = x0;
735736
Register scratch = x3;

src/compiler/ast-graph-builder.cc

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -470,15 +470,21 @@ bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) {
470470

471471
// Build receiver check for sloppy mode if necessary.
472472
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
473-
Node* original_receiver = env.Lookup(scope->receiver());
474-
Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
475-
env.Bind(scope->receiver(), patched_receiver);
473+
Node* patched_receiver = nullptr;
474+
if (scope->has_this_declaration()) {
475+
Node* original_receiver = NewNode(common()->Parameter(0), graph()->start());
476+
patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
477+
if (scope->receiver()->IsStackAllocated()) {
478+
env.Bind(scope->receiver(), patched_receiver);
479+
}
480+
}
476481

477482
// Build function context only if there are context allocated variables.
478483
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
479484
if (heap_slots > 0) {
480485
// Push a new inner context scope for the function.
481-
Node* inner_context = BuildLocalFunctionContext(function_context_.get());
486+
Node* inner_context =
487+
BuildLocalFunctionContext(function_context_.get(), patched_receiver);
482488
ContextScope top_context(this, scope, inner_context);
483489
CreateGraphBody(stack_check);
484490
} else {
@@ -2167,7 +2173,23 @@ void AstGraphBuilder::VisitCall(Call* expr) {
21672173
// Create node to ask for help resolving potential eval call. This will
21682174
// provide a fully resolved callee and the corresponding receiver.
21692175
Node* function = GetFunctionClosure();
2170-
Node* receiver = environment()->Lookup(info()->scope()->receiver());
2176+
// TODO(wingo): ResolvePossibleDirectEval doesn't really need a receiver,
2177+
// now that eval scopes don't have "this" declarations. Remove this hack
2178+
// once ResolvePossibleDirectEval changes.
2179+
Node* receiver;
2180+
{
2181+
Variable* variable = info()->scope()->LookupThis();
2182+
if (variable->IsStackAllocated()) {
2183+
receiver = environment()->Lookup(variable);
2184+
} else {
2185+
DCHECK(variable->IsContextSlot());
2186+
int depth = current_scope()->ContextChainLength(variable->scope());
2187+
bool immutable = variable->maybe_assigned() == kNotAssigned;
2188+
const Operator* op =
2189+
javascript()->LoadContext(depth, variable->index(), immutable);
2190+
receiver = NewNode(op, current_context());
2191+
}
2192+
}
21712193
Node* language = jsgraph()->Constant(language_mode());
21722194
Node* position = jsgraph()->Constant(info()->scope()->start_position());
21732195
const Operator* op =
@@ -2658,25 +2680,36 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
26582680
}
26592681

26602682

2661-
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context) {
2683+
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context,
2684+
Node* patched_receiver) {
2685+
Scope* scope = info()->scope();
26622686
Node* closure = GetFunctionClosure();
26632687

26642688
// Allocate a new local context.
26652689
Node* local_context =
2666-
info()->scope()->is_script_scope()
2667-
? BuildLocalScriptContext(info()->scope())
2690+
scope->is_script_scope()
2691+
? BuildLocalScriptContext(scope)
26682692
: NewNode(javascript()->CreateFunctionContext(), closure);
26692693

2694+
if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
2695+
DCHECK_NOT_NULL(patched_receiver);
2696+
// Context variable (at bottom of the context chain).
2697+
Variable* variable = scope->receiver();
2698+
DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
2699+
const Operator* op = javascript()->StoreContext(0, variable->index());
2700+
NewNode(op, local_context, patched_receiver);
2701+
}
2702+
26702703
// Copy parameters into context if necessary.
2671-
int num_parameters = info()->scope()->num_parameters();
2704+
int num_parameters = scope->num_parameters();
26722705
for (int i = 0; i < num_parameters; i++) {
2673-
Variable* variable = info()->scope()->parameter(i);
2706+
Variable* variable = scope->parameter(i);
26742707
if (!variable->IsContextSlot()) continue;
26752708
// Temporary parameter node. The parameter indices are shifted by 1
26762709
// (receiver is parameter index -1 but environment index 0).
26772710
Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
26782711
// Context variable (at bottom of the context chain).
2679-
DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
2712+
DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
26802713
const Operator* op = javascript()->StoreContext(0, variable->index());
26812714
NewNode(op, local_context, parameter);
26822715
}

src/compiler/ast-graph-builder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class AstGraphBuilder : public AstVisitor {
246246
Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
247247

248248
// Builders to create local function, script and block contexts.
249-
Node* BuildLocalFunctionContext(Node* context);
249+
Node* BuildLocalFunctionContext(Node* context, Node* patched_receiver);
250250
Node* BuildLocalScriptContext(Scope* scope);
251251
Node* BuildLocalBlockContext(Scope* scope);
252252

src/contexts.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,13 @@ Handle<Object> Context::Lookup(Handle<String> name,
258258
object->IsJSContextExtensionObject()) {
259259
maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
260260
} else if (context->IsWithContext()) {
261-
LookupIterator it(object, name);
262-
maybe = UnscopableLookup(&it);
261+
// A with context will never bind "this".
262+
if (name->Equals(*isolate->factory()->this_string())) {
263+
maybe = Just(ABSENT);
264+
} else {
265+
LookupIterator it(object, name);
266+
maybe = UnscopableLookup(&it);
267+
}
263268
} else {
264269
maybe = JSReceiver::GetPropertyAttributes(object, name);
265270
}

src/heap/heap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ namespace internal {
231231
V(source_string, "source") \
232232
V(source_url_string, "source_url") \
233233
V(source_mapping_url_string, "source_mapping_url") \
234+
V(this_string, "this") \
234235
V(global_string, "global") \
235236
V(ignore_case_string, "ignoreCase") \
236237
V(multiline_string, "multiline") \

src/ia32/full-codegen-ia32.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ void FullCodeGenerator::Generate() {
210210

211211
// Copy parameters into context if necessary.
212212
int num_parameters = info->scope()->num_parameters();
213-
for (int i = 0; i < num_parameters; i++) {
214-
Variable* var = scope()->parameter(i);
213+
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
214+
for (int i = first_parameter; i < num_parameters; i++) {
215+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
215216
if (var->IsContextSlot()) {
216217
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
217218
(num_parameters - 1 - i) * kPointerSize;
@@ -2959,7 +2960,9 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
29592960
// Push the enclosing function.
29602961
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
29612962
// Push the receiver of the enclosing function.
2962-
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
2963+
Variable* this_var = scope()->LookupThis();
2964+
DCHECK_NOT_NULL(this_var);
2965+
__ push(VarOperand(this_var, ecx));
29632966
// Push the language mode.
29642967
__ push(Immediate(Smi::FromInt(language_mode())));
29652968

src/ia32/lithium-codegen-ia32.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ bool LCodeGen::GeneratePrologue() {
141141
// Sloppy mode functions and builtins need to replace the receiver with the
142142
// global proxy when called as functions (without an explicit receiver
143143
// object).
144-
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
145-
!info_->is_native()) {
144+
if (is_sloppy(info()->language_mode()) && info()->MayUseThis() &&
145+
!info()->is_native() && info()->scope()->has_this_declaration()) {
146146
Label ok;
147147
// +1 for return address.
148148
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
@@ -275,8 +275,9 @@ bool LCodeGen::GeneratePrologue() {
275275

276276
// Copy parameters into context if necessary.
277277
int num_parameters = scope()->num_parameters();
278-
for (int i = 0; i < num_parameters; i++) {
279-
Variable* var = scope()->parameter(i);
278+
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
279+
for (int i = first_parameter; i < num_parameters; i++) {
280+
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
280281
if (var->IsContextSlot()) {
281282
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
282283
(num_parameters - 1 - i) * kPointerSize;

0 commit comments

Comments
 (0)