Revert "Resolve references to "this" the same way as normal variables"
... and the following two "PPC: Resolve references to "this" the same way as normal variables" "Remove Scope::scope_uses_this_ flag" R=hablich@chromium.org BUG=chromium:487289 LOG=N Review URL: https://codereview.chromium.org/1134003003 Cr-Commit-Position: refs/heads/master@{#28395}
This commit is contained in:
parent
96f8baac66
commit
e24b31f003
@ -127,7 +127,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
||||||
__ ldr(r2, MemOperand(sp, receiver_offset));
|
__ ldr(r2, MemOperand(sp, receiver_offset));
|
||||||
@ -216,9 +216,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -3068,9 +3067,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
__ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
|
|
||||||
// r3: the receiver of the enclosing function.
|
// r3: the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
int receiver_offset = 2 + info_->scope()->num_parameters();
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize));
|
||||||
__ ldr(r3, VarOperand(this_var, r3));
|
|
||||||
|
|
||||||
// r2: language mode.
|
// r2: language mode.
|
||||||
__ mov(r2, Operand(Smi::FromInt(language_mode())));
|
__ mov(r2, Operand(Smi::FromInt(language_mode())));
|
||||||
|
@ -121,7 +121,7 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info_->is_native() && info_->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
||||||
__ ldr(r2, MemOperand(sp, receiver_offset));
|
__ ldr(r2, MemOperand(sp, receiver_offset));
|
||||||
@ -197,9 +197,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -125,7 +125,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info->scope()->num_parameters() * kXRegSize;
|
int receiver_offset = info->scope()->num_parameters() * kXRegSize;
|
||||||
__ Peek(x10, receiver_offset);
|
__ Peek(x10, receiver_offset);
|
||||||
@ -217,9 +217,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -2753,9 +2752,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
|
|
||||||
__ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
// Prepare to push the receiver of the enclosing function.
|
// Prepare to push the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
int receiver_offset = 2 + info_->scope()->num_parameters();
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize));
|
||||||
__ Ldr(x11, VarOperand(this_var, x11));
|
|
||||||
|
|
||||||
// Prepare to push the language mode.
|
// Prepare to push the language mode.
|
||||||
__ Mov(x12, Smi::FromInt(language_mode()));
|
__ Mov(x12, Smi::FromInt(language_mode()));
|
||||||
|
@ -669,7 +669,7 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info()->is_native() && info()->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
|
int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
|
||||||
__ Peek(x10, receiver_offset);
|
__ Peek(x10, receiver_offset);
|
||||||
@ -728,9 +728,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
Register value = x0;
|
Register value = x0;
|
||||||
Register scratch = x3;
|
Register scratch = x3;
|
||||||
|
@ -223,7 +223,8 @@ bool CompilationInfo::is_simple_parameter_list() {
|
|||||||
|
|
||||||
|
|
||||||
bool CompilationInfo::MayUseThis() const {
|
bool CompilationInfo::MayUseThis() const {
|
||||||
return scope()->has_this_declaration() && scope()->receiver()->is_used();
|
return scope()->uses_this() || scope()->inner_uses_this() ||
|
||||||
|
scope()->calls_sloppy_eval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -512,21 +512,15 @@ bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) {
|
|||||||
|
|
||||||
// Build receiver check for sloppy mode if necessary.
|
// Build receiver check for sloppy mode if necessary.
|
||||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||||
Node* patched_receiver = nullptr;
|
Node* original_receiver = env.Lookup(scope->receiver());
|
||||||
if (scope->has_this_declaration()) {
|
Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
|
||||||
Node* original_receiver = NewNode(common()->Parameter(0), graph()->start());
|
env.Bind(scope->receiver(), patched_receiver);
|
||||||
patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
|
|
||||||
if (scope->receiver()->IsStackAllocated()) {
|
|
||||||
env.Bind(scope->receiver(), patched_receiver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build function context only if there are context allocated variables.
|
// Build function context only if there are context allocated variables.
|
||||||
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
||||||
if (heap_slots > 0) {
|
if (heap_slots > 0) {
|
||||||
// Push a new inner context scope for the function.
|
// Push a new inner context scope for the function.
|
||||||
Node* inner_context =
|
Node* inner_context = BuildLocalFunctionContext(function_context_.get());
|
||||||
BuildLocalFunctionContext(function_context_.get(), patched_receiver);
|
|
||||||
ContextScope top_context(this, scope, inner_context);
|
ContextScope top_context(this, scope, inner_context);
|
||||||
CreateGraphBody(stack_check);
|
CreateGraphBody(stack_check);
|
||||||
} else {
|
} else {
|
||||||
@ -2256,23 +2250,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
|
|||||||
// Create node to ask for help resolving potential eval call. This will
|
// Create node to ask for help resolving potential eval call. This will
|
||||||
// provide a fully resolved callee and the corresponding receiver.
|
// provide a fully resolved callee and the corresponding receiver.
|
||||||
Node* function = GetFunctionClosure();
|
Node* function = GetFunctionClosure();
|
||||||
// TODO(wingo): ResolvePossibleDirectEval doesn't really need a receiver,
|
Node* receiver = environment()->Lookup(info()->scope()->receiver());
|
||||||
// now that eval scopes don't have "this" declarations. Remove this hack
|
|
||||||
// once ResolvePossibleDirectEval changes.
|
|
||||||
Node* receiver;
|
|
||||||
{
|
|
||||||
Variable* variable = info()->scope()->LookupThis();
|
|
||||||
if (variable->IsStackAllocated()) {
|
|
||||||
receiver = environment()->Lookup(variable);
|
|
||||||
} else {
|
|
||||||
DCHECK(variable->IsContextSlot());
|
|
||||||
int depth = current_scope()->ContextChainLength(variable->scope());
|
|
||||||
bool immutable = variable->maybe_assigned() == kNotAssigned;
|
|
||||||
const Operator* op =
|
|
||||||
javascript()->LoadContext(depth, variable->index(), immutable);
|
|
||||||
receiver = NewNode(op, current_context());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Node* language = jsgraph()->Constant(language_mode());
|
Node* language = jsgraph()->Constant(language_mode());
|
||||||
Node* position = jsgraph()->Constant(info()->scope()->start_position());
|
Node* position = jsgraph()->Constant(info()->scope()->start_position());
|
||||||
const Operator* op =
|
const Operator* op =
|
||||||
@ -2752,7 +2730,9 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
|
|||||||
// object). Otherwise there is nothing left to do here.
|
// object). Otherwise there is nothing left to do here.
|
||||||
if (is_strict(language_mode()) || info()->is_native()) return receiver;
|
if (is_strict(language_mode()) || info()->is_native()) return receiver;
|
||||||
|
|
||||||
// There is no need to perform patching if the receiver will never be used.
|
// There is no need to perform patching if the receiver is never used. Note
|
||||||
|
// that scope predicates are purely syntactical, a call to eval might still
|
||||||
|
// inspect the receiver value.
|
||||||
if (!info()->MayUseThis()) return receiver;
|
if (!info()->MayUseThis()) return receiver;
|
||||||
|
|
||||||
IfBuilder receiver_check(this);
|
IfBuilder receiver_check(this);
|
||||||
@ -2769,36 +2749,25 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context,
|
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context) {
|
||||||
Node* patched_receiver) {
|
|
||||||
Scope* scope = info()->scope();
|
|
||||||
Node* closure = GetFunctionClosure();
|
Node* closure = GetFunctionClosure();
|
||||||
|
|
||||||
// Allocate a new local context.
|
// Allocate a new local context.
|
||||||
Node* local_context =
|
Node* local_context =
|
||||||
scope->is_script_scope()
|
info()->scope()->is_script_scope()
|
||||||
? BuildLocalScriptContext(scope)
|
? BuildLocalScriptContext(info()->scope())
|
||||||
: NewNode(javascript()->CreateFunctionContext(), closure);
|
: NewNode(javascript()->CreateFunctionContext(), closure);
|
||||||
|
|
||||||
if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
|
|
||||||
DCHECK_NOT_NULL(patched_receiver);
|
|
||||||
// Context variable (at bottom of the context chain).
|
|
||||||
Variable* variable = scope->receiver();
|
|
||||||
DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
|
|
||||||
const Operator* op = javascript()->StoreContext(0, variable->index());
|
|
||||||
NewNode(op, local_context, patched_receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy parameters into context if necessary.
|
// Copy parameters into context if necessary.
|
||||||
int num_parameters = scope->num_parameters();
|
int num_parameters = info()->scope()->num_parameters();
|
||||||
for (int i = 0; i < num_parameters; i++) {
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
Variable* variable = scope->parameter(i);
|
Variable* variable = info()->scope()->parameter(i);
|
||||||
if (!variable->IsContextSlot()) continue;
|
if (!variable->IsContextSlot()) continue;
|
||||||
// Temporary parameter node. The parameter indices are shifted by 1
|
// Temporary parameter node. The parameter indices are shifted by 1
|
||||||
// (receiver is parameter index -1 but environment index 0).
|
// (receiver is parameter index -1 but environment index 0).
|
||||||
Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
|
Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
|
||||||
// Context variable (at bottom of the context chain).
|
// Context variable (at bottom of the context chain).
|
||||||
DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
|
DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
|
||||||
const Operator* op = javascript()->StoreContext(0, variable->index());
|
const Operator* op = javascript()->StoreContext(0, variable->index());
|
||||||
NewNode(op, local_context, parameter);
|
NewNode(op, local_context, parameter);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ class AstGraphBuilder : public AstVisitor {
|
|||||||
Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
|
Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
|
||||||
|
|
||||||
// Builders to create local function, script and block contexts.
|
// Builders to create local function, script and block contexts.
|
||||||
Node* BuildLocalFunctionContext(Node* context, Node* patched_receiver);
|
Node* BuildLocalFunctionContext(Node* context);
|
||||||
Node* BuildLocalScriptContext(Scope* scope);
|
Node* BuildLocalScriptContext(Scope* scope);
|
||||||
Node* BuildLocalBlockContext(Scope* scope);
|
Node* BuildLocalBlockContext(Scope* scope);
|
||||||
|
|
||||||
|
@ -258,13 +258,8 @@ Handle<Object> Context::Lookup(Handle<String> name,
|
|||||||
object->IsJSContextExtensionObject()) {
|
object->IsJSContextExtensionObject()) {
|
||||||
maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
|
maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
|
||||||
} else if (context->IsWithContext()) {
|
} else if (context->IsWithContext()) {
|
||||||
// A with context will never bind "this".
|
LookupIterator it(object, name);
|
||||||
if (name->Equals(*isolate->factory()->this_string())) {
|
maybe = UnscopableLookup(&it);
|
||||||
maybe = Just(ABSENT);
|
|
||||||
} else {
|
|
||||||
LookupIterator it(object, name);
|
|
||||||
maybe = UnscopableLookup(&it);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
maybe = JSReceiver::GetPropertyAttributes(object, name);
|
maybe = JSReceiver::GetPropertyAttributes(object, name);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,6 @@ namespace internal {
|
|||||||
V(source_string, "source") \
|
V(source_string, "source") \
|
||||||
V(source_url_string, "source_url") \
|
V(source_url_string, "source_url") \
|
||||||
V(source_mapping_url_string, "source_mapping_url") \
|
V(source_mapping_url_string, "source_mapping_url") \
|
||||||
V(this_string, "this") \
|
|
||||||
V(global_string, "global") \
|
V(global_string, "global") \
|
||||||
V(ignore_case_string, "ignoreCase") \
|
V(ignore_case_string, "ignoreCase") \
|
||||||
V(multiline_string, "multiline") \
|
V(multiline_string, "multiline") \
|
||||||
|
@ -210,9 +210,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
|
|
||||||
// Copy parameters into context if necessary.
|
// Copy parameters into context if necessary.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -2961,9 +2960,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
// Push the enclosing function.
|
// Push the enclosing function.
|
||||||
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
// Push the receiver of the enclosing function.
|
// Push the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
|
||||||
DCHECK_NOT_NULL(this_var);
|
|
||||||
__ push(VarOperand(this_var, ecx));
|
|
||||||
// Push the language mode.
|
// Push the language mode.
|
||||||
__ push(Immediate(Smi::FromInt(language_mode())));
|
__ push(Immediate(Smi::FromInt(language_mode())));
|
||||||
|
|
||||||
|
@ -141,8 +141,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info()->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info()->is_native() && info()->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
// +1 for return address.
|
// +1 for return address.
|
||||||
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
|
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
|
||||||
@ -275,9 +275,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
|
|
||||||
// Copy parameters into context if necessary.
|
// Copy parameters into context if necessary.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -135,7 +135,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
||||||
__ lw(at, MemOperand(sp, receiver_offset));
|
__ lw(at, MemOperand(sp, receiver_offset));
|
||||||
@ -225,9 +225,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
__ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -3039,9 +3038,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
__ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
|
|
||||||
// t1: the receiver of the enclosing function.
|
// t1: the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
int receiver_offset = 2 + info_->scope()->num_parameters();
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ lw(t1, MemOperand(fp, receiver_offset * kPointerSize));
|
||||||
__ lw(t1, VarOperand(this_var, t1));
|
|
||||||
|
|
||||||
// t0: the language mode.
|
// t0: the language mode.
|
||||||
__ li(t0, Operand(Smi::FromInt(language_mode())));
|
__ li(t0, Operand(Smi::FromInt(language_mode())));
|
||||||
|
@ -143,8 +143,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info()->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info()->is_native() && info()->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
||||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||||
@ -217,9 +217,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -135,7 +135,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
||||||
__ ld(at, MemOperand(sp, receiver_offset));
|
__ ld(at, MemOperand(sp, receiver_offset));
|
||||||
@ -222,9 +222,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
__ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -3041,9 +3040,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
__ ld(a6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ ld(a6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
|
|
||||||
// a5: the receiver of the enclosing function.
|
// a5: the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
int receiver_offset = 2 + info_->scope()->num_parameters();
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ ld(a5, MemOperand(fp, receiver_offset * kPointerSize));
|
||||||
__ ld(a5, VarOperand(this_var, a5));
|
|
||||||
|
|
||||||
// a4: the language mode.
|
// a4: the language mode.
|
||||||
__ li(a4, Operand(Smi::FromInt(language_mode())));
|
__ li(a4, Operand(Smi::FromInt(language_mode())));
|
||||||
|
@ -118,8 +118,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info()->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info()->is_native() && info()->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
||||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||||
@ -192,9 +192,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -741,9 +741,7 @@ const AstRawString* ParserTraits::GetNextSymbol(Scanner* scanner) {
|
|||||||
|
|
||||||
Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
|
Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
|
||||||
int pos) {
|
int pos) {
|
||||||
return scope->NewUnresolved(factory,
|
return factory->NewVariableProxy(scope->receiver(), pos);
|
||||||
parser_->ast_value_factory()->this_string(),
|
|
||||||
Variable::THIS, pos, pos + 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory,
|
Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory,
|
||||||
@ -791,8 +789,7 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
|
|||||||
Scope* scope,
|
Scope* scope,
|
||||||
AstNodeFactory* factory) {
|
AstNodeFactory* factory) {
|
||||||
if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
|
if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
|
||||||
return scope->NewUnresolved(factory, name, Variable::NORMAL, start_position,
|
return scope->NewUnresolved(factory, name, start_position, end_position);
|
||||||
end_position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -971,8 +968,6 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
|
|||||||
|
|
||||||
FunctionLiteral* result = NULL;
|
FunctionLiteral* result = NULL;
|
||||||
{
|
{
|
||||||
// TODO(wingo): Add an outer GLOBAL_SCOPE corresponding to the native
|
|
||||||
// context, which will have the "this" binding for script scopes.
|
|
||||||
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
|
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
|
||||||
info->set_script_scope(scope);
|
info->set_script_scope(scope);
|
||||||
if (!info->context().is_null() && !info->context()->IsNativeContext()) {
|
if (!info->context().is_null() && !info->context()->IsNativeContext()) {
|
||||||
@ -1923,9 +1918,9 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name,
|
|||||||
// scope.
|
// scope.
|
||||||
// Let/const variables in harmony mode are always added to the immediately
|
// Let/const variables in harmony mode are always added to the immediately
|
||||||
// enclosing scope.
|
// enclosing scope.
|
||||||
return DeclarationScope(mode)->NewUnresolved(
|
return DeclarationScope(mode)->NewUnresolved(factory(), name,
|
||||||
factory(), name, Variable::NORMAL, scanner()->location().beg_pos,
|
scanner()->location().beg_pos,
|
||||||
scanner()->location().end_pos);
|
scanner()->location().end_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3438,8 +3433,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
|||||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
|
|
||||||
VariableProxy* each = scope_->NewUnresolved(
|
VariableProxy* each =
|
||||||
factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
|
scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos);
|
||||||
Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
||||||
InitializeForEachStatement(loop, each, enumerable, body);
|
InitializeForEachStatement(loop, each, enumerable, body);
|
||||||
Block* result =
|
Block* result =
|
||||||
@ -3520,8 +3515,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
|||||||
scope_ = for_scope;
|
scope_ = for_scope;
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
|
|
||||||
VariableProxy* each = scope_->NewUnresolved(
|
VariableProxy* each =
|
||||||
factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
|
scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos);
|
||||||
Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
||||||
Block* body_block =
|
Block* body_block =
|
||||||
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
|
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
|
||||||
|
@ -124,7 +124,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
||||||
__ LoadP(r5, MemOperand(sp, receiver_offset), r0);
|
__ LoadP(r5, MemOperand(sp, receiver_offset), r0);
|
||||||
@ -221,9 +221,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
__ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -3051,9 +3050,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
__ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
|
|
||||||
// r6: the receiver of the enclosing function.
|
// r6: the receiver of the enclosing function.
|
||||||
Variable* this_var = scope()->LookupThis();
|
int receiver_offset = 2 + info_->scope()->num_parameters();
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ LoadP(r6, MemOperand(fp, receiver_offset * kPointerSize), r0);
|
||||||
GetVar(r6, this_var);
|
|
||||||
|
|
||||||
// r5: language mode.
|
// r5: language mode.
|
||||||
__ LoadSmiLiteral(r5, Smi::FromInt(language_mode()));
|
__ LoadSmiLiteral(r5, Smi::FromInt(language_mode()));
|
||||||
|
@ -118,8 +118,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info_->language_mode()) && info_->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info_->is_native() && info_->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
||||||
__ LoadP(r5, MemOperand(sp, receiver_offset));
|
__ LoadP(r5, MemOperand(sp, receiver_offset));
|
||||||
@ -199,9 +199,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -2282,6 +2282,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
scope_->RecordThisUsage();
|
||||||
result = this->ThisExpression(scope_, factory(), beg_pos);
|
result = this->ThisExpression(scope_, factory(), beg_pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3354,6 +3355,7 @@ ParserBase<Traits>::ParseStrongInitializationExpression(
|
|||||||
Consume(Token::THIS);
|
Consume(Token::THIS);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
function_state_->set_this_location(scanner()->location());
|
function_state_->set_this_location(scanner()->location());
|
||||||
|
scope_->RecordThisUsage();
|
||||||
ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
|
ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
|
||||||
|
|
||||||
ExpressionT left = this->EmptyExpression();
|
ExpressionT left = this->EmptyExpression();
|
||||||
|
@ -1475,21 +1475,16 @@ class ScopeIterator {
|
|||||||
context_ = Handle<Context>();
|
context_ = Handle<Context>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scope_type == ScopeTypeScript) {
|
if (scope_type == ScopeTypeScript) seen_script_scope_ = true;
|
||||||
seen_script_scope_ = true;
|
if (nested_scope_chain_.is_empty()) {
|
||||||
if (context_->IsScriptContext()) {
|
if (scope_type == ScopeTypeScript) {
|
||||||
|
if (context_->IsScriptContext()) {
|
||||||
|
context_ = Handle<Context>(context_->previous(), isolate_);
|
||||||
|
}
|
||||||
|
CHECK(context_->IsNativeContext());
|
||||||
|
} else {
|
||||||
context_ = Handle<Context>(context_->previous(), isolate_);
|
context_ = Handle<Context>(context_->previous(), isolate_);
|
||||||
}
|
}
|
||||||
if (!nested_scope_chain_.is_empty()) {
|
|
||||||
DCHECK_EQ(nested_scope_chain_.last()->scope_type(), SCRIPT_SCOPE);
|
|
||||||
nested_scope_chain_.RemoveLast();
|
|
||||||
DCHECK(nested_scope_chain_.is_empty());
|
|
||||||
}
|
|
||||||
CHECK(context_->IsNativeContext());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nested_scope_chain_.is_empty()) {
|
|
||||||
context_ = Handle<Context>(context_->previous(), isolate_);
|
|
||||||
} else {
|
} else {
|
||||||
if (nested_scope_chain_.last()->HasContext()) {
|
if (nested_scope_chain_.last()->HasContext()) {
|
||||||
DCHECK(context_->previous() != NULL);
|
DCHECK(context_->previous() != NULL);
|
||||||
|
@ -248,12 +248,6 @@ RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
|
|||||||
JSGlobalObject::cast(context_arg->extension()), isolate);
|
JSGlobalObject::cast(context_arg->extension()), isolate);
|
||||||
return DeclareGlobals(isolate, global, name, value, attr, is_var, is_const,
|
return DeclareGlobals(isolate, global, name, value, attr, is_var, is_const,
|
||||||
is_function);
|
is_function);
|
||||||
} else if (context->IsScriptContext()) {
|
|
||||||
DCHECK(context->global_object()->IsJSGlobalObject());
|
|
||||||
Handle<JSGlobalObject> global(
|
|
||||||
JSGlobalObject::cast(context->global_object()), isolate);
|
|
||||||
return DeclareGlobals(isolate, global, name, value, attr, is_var, is_const,
|
|
||||||
is_function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes != ABSENT) {
|
if (attributes != ABSENT) {
|
||||||
@ -329,12 +323,8 @@ RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
|
|||||||
// meanwhile. If so, re-introduce the variable in the context extension.
|
// meanwhile. If so, re-introduce the variable in the context extension.
|
||||||
if (attributes == ABSENT) {
|
if (attributes == ABSENT) {
|
||||||
Handle<Context> declaration_context(context_arg->declaration_context());
|
Handle<Context> declaration_context(context_arg->declaration_context());
|
||||||
if (declaration_context->IsScriptContext()) {
|
DCHECK(declaration_context->has_extension());
|
||||||
holder = handle(declaration_context->global_object(), isolate);
|
holder = handle(declaration_context->extension(), isolate);
|
||||||
} else {
|
|
||||||
DCHECK(declaration_context->has_extension());
|
|
||||||
holder = handle(declaration_context->extension(), isolate);
|
|
||||||
}
|
|
||||||
CHECK(holder->IsJSObject());
|
CHECK(holder->IsJSObject());
|
||||||
} else {
|
} else {
|
||||||
// For JSContextExtensionObjects, the initializer can be run multiple times
|
// For JSContextExtensionObjects, the initializer can be run multiple times
|
||||||
@ -638,12 +628,8 @@ RUNTIME_FUNCTION(Runtime_NewScriptContext) {
|
|||||||
FindNameClash(scope_info, global_object, script_context_table);
|
FindNameClash(scope_info, global_object, script_context_table);
|
||||||
if (isolate->has_pending_exception()) return name_clash_result;
|
if (isolate->has_pending_exception()) return name_clash_result;
|
||||||
|
|
||||||
// Script contexts have a canonical empty function as their closure, not the
|
|
||||||
// anonymous closure containing the global code. See
|
|
||||||
// FullCodeGenerator::PushFunctionArgumentForContextAllocation.
|
|
||||||
Handle<JSFunction> closure(native_context->closure());
|
|
||||||
Handle<Context> result =
|
Handle<Context> result =
|
||||||
isolate->factory()->NewScriptContext(closure, scope_info);
|
isolate->factory()->NewScriptContext(function, scope_info);
|
||||||
|
|
||||||
DCHECK(function->context() == isolate->context());
|
DCHECK(function->context() == isolate->context());
|
||||||
DCHECK(function->context()->global_object() == result->global_object());
|
DCHECK(function->context()->global_object() == result->global_object());
|
||||||
|
@ -317,8 +317,7 @@ bool ScopeInfo::LocalIsSynthetic(int var) {
|
|||||||
// with user declarations, the current temporaries like .generator_object and
|
// with user declarations, the current temporaries like .generator_object and
|
||||||
// .result start with a dot, so we can use that as a flag. It's a hack!
|
// .result start with a dot, so we can use that as a flag. It's a hack!
|
||||||
Handle<String> name(LocalName(var));
|
Handle<String> name(LocalName(var));
|
||||||
return (name->length() > 0 && name->Get(0) == '.') ||
|
return name->length() > 0 && name->Get(0) == '.';
|
||||||
name->Equals(*GetIsolate()->factory()->this_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
|||||||
scope_calls_eval_ = false;
|
scope_calls_eval_ = false;
|
||||||
scope_uses_arguments_ = false;
|
scope_uses_arguments_ = false;
|
||||||
scope_uses_super_property_ = false;
|
scope_uses_super_property_ = false;
|
||||||
|
scope_uses_this_ = false;
|
||||||
asm_module_ = false;
|
asm_module_ = false;
|
||||||
asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
|
asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
|
||||||
// Inherit the language mode from the parent scope.
|
// Inherit the language mode from the parent scope.
|
||||||
@ -172,6 +173,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
|||||||
outer_scope_calls_sloppy_eval_ = false;
|
outer_scope_calls_sloppy_eval_ = false;
|
||||||
inner_scope_calls_eval_ = false;
|
inner_scope_calls_eval_ = false;
|
||||||
inner_scope_uses_arguments_ = false;
|
inner_scope_uses_arguments_ = false;
|
||||||
|
inner_scope_uses_this_ = false;
|
||||||
inner_scope_uses_super_property_ = false;
|
inner_scope_uses_super_property_ = false;
|
||||||
force_eager_compilation_ = false;
|
force_eager_compilation_ = false;
|
||||||
force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
|
force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
|
||||||
@ -307,16 +309,22 @@ void Scope::Initialize() {
|
|||||||
scope_inside_with_ = is_with_scope();
|
scope_inside_with_ = is_with_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declare convenience variables and the receiver.
|
// Declare convenience variables.
|
||||||
|
// Declare and allocate receiver (even for the script scope, and even
|
||||||
|
// if naccesses_ == 0).
|
||||||
|
// NOTE: When loading parameters in the script scope, we must take
|
||||||
|
// care not to access them as properties of the global object, but
|
||||||
|
// instead load them directly from the stack. Currently, the only
|
||||||
|
// such parameter is 'this' which is passed on the stack when
|
||||||
|
// invoking scripts
|
||||||
if (is_declaration_scope()) {
|
if (is_declaration_scope()) {
|
||||||
DCHECK(!subclass_constructor || is_function_scope());
|
DCHECK(!subclass_constructor || is_function_scope());
|
||||||
if (has_this_declaration()) {
|
Variable* var = variables_.Declare(
|
||||||
Variable* var = variables_.Declare(
|
this, ast_value_factory_->this_string(),
|
||||||
this, ast_value_factory_->this_string(),
|
subclass_constructor ? CONST : VAR, Variable::THIS,
|
||||||
subclass_constructor ? CONST : VAR, Variable::THIS,
|
subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
|
||||||
subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
|
var->AllocateTo(Variable::PARAMETER, -1);
|
||||||
receiver_ = var;
|
receiver_ = var;
|
||||||
}
|
|
||||||
|
|
||||||
if (subclass_constructor) {
|
if (subclass_constructor) {
|
||||||
new_target_ =
|
new_target_ =
|
||||||
@ -325,6 +333,9 @@ void Scope::Initialize() {
|
|||||||
new_target_->AllocateTo(Variable::PARAMETER, -2);
|
new_target_->AllocateTo(Variable::PARAMETER, -2);
|
||||||
new_target_->set_is_used();
|
new_target_->set_is_used();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DCHECK(outer_scope() != NULL);
|
||||||
|
receiver_ = outer_scope()->receiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_function_scope() && !is_arrow_scope()) {
|
if (is_function_scope() && !is_arrow_scope()) {
|
||||||
@ -369,6 +380,7 @@ Scope* Scope::FinalizeBlockScope() {
|
|||||||
// Propagate usage flags to outer scope.
|
// Propagate usage flags to outer scope.
|
||||||
if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
|
if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
|
||||||
if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
|
if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
|
||||||
|
if (uses_this()) outer_scope_->RecordThisUsage();
|
||||||
if (scope_calls_eval_) outer_scope_->RecordEvalCall();
|
if (scope_calls_eval_) outer_scope_->RecordEvalCall();
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -918,11 +930,13 @@ void Scope::Print(int n) {
|
|||||||
if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
|
if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
|
||||||
if (scope_uses_super_property_)
|
if (scope_uses_super_property_)
|
||||||
Indent(n1, "// scope uses 'super' property\n");
|
Indent(n1, "// scope uses 'super' property\n");
|
||||||
|
if (scope_uses_this_) Indent(n1, "// scope uses 'this'\n");
|
||||||
if (inner_scope_uses_arguments_) {
|
if (inner_scope_uses_arguments_) {
|
||||||
Indent(n1, "// inner scope uses 'arguments'\n");
|
Indent(n1, "// inner scope uses 'arguments'\n");
|
||||||
}
|
}
|
||||||
if (inner_scope_uses_super_property_)
|
if (inner_scope_uses_super_property_)
|
||||||
Indent(n1, "// inner scope uses 'super' property\n");
|
Indent(n1, "// inner scope uses 'super' property\n");
|
||||||
|
if (inner_scope_uses_this_) Indent(n1, "// inner scope uses 'this'\n");
|
||||||
if (outer_scope_calls_sloppy_eval_) {
|
if (outer_scope_calls_sloppy_eval_) {
|
||||||
Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
|
Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
|
||||||
}
|
}
|
||||||
@ -1035,11 +1049,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
|
|||||||
DCHECK(is_script_scope());
|
DCHECK(is_script_scope());
|
||||||
}
|
}
|
||||||
|
|
||||||
// "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
|
if (is_with_scope()) {
|
||||||
// TODO(wingo): There are other variables in this category; add them.
|
|
||||||
bool name_can_be_shadowed = var == nullptr || !var->is_this();
|
|
||||||
|
|
||||||
if (is_with_scope() && name_can_be_shadowed) {
|
|
||||||
DCHECK(!already_resolved());
|
DCHECK(!already_resolved());
|
||||||
// The current scope is a with scope, so the variable binding can not be
|
// The current scope is a with scope, so the variable binding can not be
|
||||||
// statically resolved. However, note that it was necessary to do a lookup
|
// statically resolved. However, note that it was necessary to do a lookup
|
||||||
@ -1050,7 +1060,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
|
|||||||
if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
|
if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
|
||||||
*binding_kind = DYNAMIC_LOOKUP;
|
*binding_kind = DYNAMIC_LOOKUP;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (calls_sloppy_eval() && name_can_be_shadowed) {
|
} else if (calls_sloppy_eval()) {
|
||||||
// A variable binding may have been found in an outer scope, but the current
|
// A variable binding may have been found in an outer scope, but the current
|
||||||
// scope makes a sloppy 'eval' call, so the found variable may not be
|
// scope makes a sloppy 'eval' call, so the found variable may not be
|
||||||
// the correct one (the 'eval' may introduce a binding with the same name).
|
// the correct one (the 'eval' may introduce a binding with the same name).
|
||||||
@ -1282,6 +1292,9 @@ void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
|
|||||||
inner->inner_scope_uses_super_property_) {
|
inner->inner_scope_uses_super_property_) {
|
||||||
inner_scope_uses_super_property_ = true;
|
inner_scope_uses_super_property_ = true;
|
||||||
}
|
}
|
||||||
|
if (inner->scope_uses_this_ || inner->inner_scope_uses_this_) {
|
||||||
|
inner_scope_uses_this_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (inner->force_eager_compilation_) {
|
if (inner->force_eager_compilation_) {
|
||||||
force_eager_compilation_ = true;
|
force_eager_compilation_ = true;
|
||||||
@ -1402,40 +1415,24 @@ void Scope::AllocateParameterLocals(Isolate* isolate) {
|
|||||||
// Force context allocation of the parameter.
|
// Force context allocation of the parameter.
|
||||||
var->ForceContextAllocation();
|
var->ForceContextAllocation();
|
||||||
}
|
}
|
||||||
AllocateParameter(var, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (MustAllocate(var)) {
|
||||||
void Scope::AllocateParameter(Variable* var, int index) {
|
if (MustAllocateInContext(var)) {
|
||||||
if (MustAllocate(var)) {
|
DCHECK(var->IsUnallocated() || var->IsContextSlot());
|
||||||
if (MustAllocateInContext(var)) {
|
if (var->IsUnallocated()) {
|
||||||
DCHECK(var->IsUnallocated() || var->IsContextSlot());
|
AllocateHeapSlot(var);
|
||||||
if (var->IsUnallocated()) {
|
}
|
||||||
AllocateHeapSlot(var);
|
} else {
|
||||||
}
|
DCHECK(var->IsUnallocated() || var->IsParameter());
|
||||||
} else {
|
if (var->IsUnallocated()) {
|
||||||
DCHECK(var->IsUnallocated() || var->IsParameter());
|
var->AllocateTo(Variable::PARAMETER, i);
|
||||||
if (var->IsUnallocated()) {
|
}
|
||||||
var->AllocateTo(Variable::PARAMETER, index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Scope::AllocateReceiver() {
|
|
||||||
DCHECK_NOT_NULL(receiver());
|
|
||||||
DCHECK_EQ(receiver()->scope(), this);
|
|
||||||
|
|
||||||
if (has_forced_context_allocation()) {
|
|
||||||
// Force context allocation of the receiver.
|
|
||||||
receiver()->ForceContextAllocation();
|
|
||||||
}
|
|
||||||
AllocateParameter(receiver(), -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
|
void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
|
||||||
DCHECK(var->scope() == this);
|
DCHECK(var->scope() == this);
|
||||||
DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
|
DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
|
||||||
@ -1505,7 +1502,6 @@ void Scope::AllocateVariablesRecursively(Isolate* isolate) {
|
|||||||
// Allocate variables for this scope.
|
// Allocate variables for this scope.
|
||||||
// Parameters must be allocated first, if any.
|
// Parameters must be allocated first, if any.
|
||||||
if (is_function_scope()) AllocateParameterLocals(isolate);
|
if (is_function_scope()) AllocateParameterLocals(isolate);
|
||||||
if (has_this_declaration()) AllocateReceiver();
|
|
||||||
AllocateNonParameterLocals(isolate);
|
AllocateNonParameterLocals(isolate);
|
||||||
|
|
||||||
// Force allocation of a context for this scope if necessary. For a 'with'
|
// Force allocation of a context for this scope if necessary. For a 'with'
|
||||||
|
33
src/scopes.h
33
src/scopes.h
@ -144,15 +144,14 @@ class Scope: public ZoneObject {
|
|||||||
// Create a new unresolved variable.
|
// Create a new unresolved variable.
|
||||||
VariableProxy* NewUnresolved(AstNodeFactory* factory,
|
VariableProxy* NewUnresolved(AstNodeFactory* factory,
|
||||||
const AstRawString* name,
|
const AstRawString* name,
|
||||||
Variable::Kind kind = Variable::NORMAL,
|
|
||||||
int start_position = RelocInfo::kNoPosition,
|
int start_position = RelocInfo::kNoPosition,
|
||||||
int end_position = RelocInfo::kNoPosition) {
|
int end_position = RelocInfo::kNoPosition) {
|
||||||
// Note that we must not share the unresolved variables with
|
// Note that we must not share the unresolved variables with
|
||||||
// the same name because they may be removed selectively via
|
// the same name because they may be removed selectively via
|
||||||
// RemoveUnresolved().
|
// RemoveUnresolved().
|
||||||
DCHECK(!already_resolved());
|
DCHECK(!already_resolved());
|
||||||
VariableProxy* proxy =
|
VariableProxy* proxy = factory->NewVariableProxy(
|
||||||
factory->NewVariableProxy(name, kind, start_position, end_position);
|
name, Variable::NORMAL, start_position, end_position);
|
||||||
unresolved_.Add(proxy, zone_);
|
unresolved_.Add(proxy, zone_);
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
@ -218,6 +217,9 @@ class Scope: public ZoneObject {
|
|||||||
// Inform the scope that the corresponding code uses "super".
|
// Inform the scope that the corresponding code uses "super".
|
||||||
void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
|
void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
|
||||||
|
|
||||||
|
// Inform the scope that the corresponding code uses "this".
|
||||||
|
void RecordThisUsage() { scope_uses_this_ = true; }
|
||||||
|
|
||||||
// Set the language mode flag (unless disabled by a global flag).
|
// Set the language mode flag (unless disabled by a global flag).
|
||||||
void SetLanguageMode(LanguageMode language_mode) {
|
void SetLanguageMode(LanguageMode language_mode) {
|
||||||
language_mode_ = language_mode;
|
language_mode_ = language_mode;
|
||||||
@ -321,6 +323,10 @@ class Scope: public ZoneObject {
|
|||||||
bool inner_uses_super_property() const {
|
bool inner_uses_super_property() const {
|
||||||
return inner_scope_uses_super_property_;
|
return inner_scope_uses_super_property_;
|
||||||
}
|
}
|
||||||
|
// Does this scope access "this".
|
||||||
|
bool uses_this() const { return scope_uses_this_; }
|
||||||
|
// Does any inner scope access "this".
|
||||||
|
bool inner_uses_this() const { return inner_scope_uses_this_; }
|
||||||
|
|
||||||
const Scope* NearestOuterEvalScope() const {
|
const Scope* NearestOuterEvalScope() const {
|
||||||
if (is_eval_scope()) return this;
|
if (is_eval_scope()) return this;
|
||||||
@ -340,21 +346,7 @@ class Scope: public ZoneObject {
|
|||||||
LanguageMode language_mode() const { return language_mode_; }
|
LanguageMode language_mode() const { return language_mode_; }
|
||||||
|
|
||||||
// The variable corresponding to the 'this' value.
|
// The variable corresponding to the 'this' value.
|
||||||
Variable* receiver() {
|
Variable* receiver() { return receiver_; }
|
||||||
DCHECK(has_this_declaration());
|
|
||||||
DCHECK_NOT_NULL(receiver_);
|
|
||||||
return receiver_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable* LookupThis() { return Lookup(ast_value_factory_->this_string()); }
|
|
||||||
|
|
||||||
// TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate
|
|
||||||
// "this" (and no other variable) on the native context. Script scopes then
|
|
||||||
// will not have a "this" declaration.
|
|
||||||
bool has_this_declaration() const {
|
|
||||||
return (is_function_scope() && !is_arrow_scope()) || is_module_scope() ||
|
|
||||||
is_script_scope();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The variable corresponding to the 'new.target' value.
|
// The variable corresponding to the 'new.target' value.
|
||||||
Variable* new_target_var() { return new_target_; }
|
Variable* new_target_var() { return new_target_; }
|
||||||
@ -585,6 +577,8 @@ class Scope: public ZoneObject {
|
|||||||
bool scope_uses_arguments_;
|
bool scope_uses_arguments_;
|
||||||
// This scope uses "super" property ('super.foo').
|
// This scope uses "super" property ('super.foo').
|
||||||
bool scope_uses_super_property_;
|
bool scope_uses_super_property_;
|
||||||
|
// This scope uses "this".
|
||||||
|
bool scope_uses_this_;
|
||||||
// This scope contains an "use asm" annotation.
|
// This scope contains an "use asm" annotation.
|
||||||
bool asm_module_;
|
bool asm_module_;
|
||||||
// This scope's outer context is an asm module.
|
// This scope's outer context is an asm module.
|
||||||
@ -600,6 +594,7 @@ class Scope: public ZoneObject {
|
|||||||
bool inner_scope_calls_eval_;
|
bool inner_scope_calls_eval_;
|
||||||
bool inner_scope_uses_arguments_;
|
bool inner_scope_uses_arguments_;
|
||||||
bool inner_scope_uses_super_property_;
|
bool inner_scope_uses_super_property_;
|
||||||
|
bool inner_scope_uses_this_;
|
||||||
bool force_eager_compilation_;
|
bool force_eager_compilation_;
|
||||||
bool force_context_allocation_;
|
bool force_context_allocation_;
|
||||||
|
|
||||||
@ -711,8 +706,6 @@ class Scope: public ZoneObject {
|
|||||||
void AllocateNonParameterLocal(Isolate* isolate, Variable* var);
|
void AllocateNonParameterLocal(Isolate* isolate, Variable* var);
|
||||||
void AllocateNonParameterLocals(Isolate* isolate);
|
void AllocateNonParameterLocals(Isolate* isolate);
|
||||||
void AllocateVariablesRecursively(Isolate* isolate);
|
void AllocateVariablesRecursively(Isolate* isolate);
|
||||||
void AllocateParameter(Variable* var, int index);
|
|
||||||
void AllocateReceiver();
|
|
||||||
void AllocateModules();
|
void AllocateModules();
|
||||||
|
|
||||||
// Resolve and fill in the allocation information for all variables
|
// Resolve and fill in the allocation information for all variables
|
||||||
|
@ -59,8 +59,8 @@ bool Variable::IsGlobalObjectProperty() const {
|
|||||||
// Temporaries are never global, they must always be allocated in the
|
// Temporaries are never global, they must always be allocated in the
|
||||||
// activation frame.
|
// activation frame.
|
||||||
return (IsDynamicVariableMode(mode_) ||
|
return (IsDynamicVariableMode(mode_) ||
|
||||||
(IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_))) &&
|
(IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_)))
|
||||||
scope_ != NULL && scope_->is_script_scope() && !is_this();
|
&& scope_ != NULL && scope_->is_script_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ void FullCodeGenerator::Generate() {
|
|||||||
// global proxy when called as functions (without an explicit receiver
|
// global proxy when called as functions (without an explicit receiver
|
||||||
// object).
|
// object).
|
||||||
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
if (is_sloppy(info->language_mode()) && !info->is_native() &&
|
||||||
info->MayUseThis() && info->scope()->has_this_declaration()) {
|
info->MayUseThis()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
// +1 for return address.
|
// +1 for return address.
|
||||||
StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
|
StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
|
||||||
@ -209,9 +209,8 @@ void FullCodeGenerator::Generate() {
|
|||||||
|
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = info->scope()->num_parameters();
|
int num_parameters = info->scope()->num_parameters();
|
||||||
int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
@ -2962,9 +2961,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
|||||||
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
|
|
||||||
// Push the receiver of the enclosing function and do runtime call.
|
// Push the receiver of the enclosing function and do runtime call.
|
||||||
Variable* this_var = scope()->LookupThis();
|
StackArgumentsAccessor args(rbp, info_->scope()->num_parameters());
|
||||||
DCHECK_NOT_NULL(this_var);
|
__ Push(args.GetReceiverOperand());
|
||||||
__ Push(VarOperand(this_var, rcx));
|
|
||||||
|
|
||||||
// Push the language mode.
|
// Push the language mode.
|
||||||
__ Push(Smi::FromInt(language_mode()));
|
__ Push(Smi::FromInt(language_mode()));
|
||||||
|
@ -129,8 +129,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
|
|
||||||
// Sloppy mode functions need to replace the receiver with the global proxy
|
// Sloppy mode functions need to replace the receiver with the global proxy
|
||||||
// when called as functions (without an explicit receiver object).
|
// when called as functions (without an explicit receiver object).
|
||||||
if (is_sloppy(info()->language_mode()) && info()->MayUseThis() &&
|
if (is_sloppy(info_->language_mode()) && info()->MayUseThis() &&
|
||||||
!info()->is_native() && info()->scope()->has_this_declaration()) {
|
!info_->is_native()) {
|
||||||
Label ok;
|
Label ok;
|
||||||
StackArgumentsAccessor args(rsp, scope()->num_parameters());
|
StackArgumentsAccessor args(rsp, scope()->num_parameters());
|
||||||
__ movp(rcx, args.GetReceiverOperand());
|
__ movp(rcx, args.GetReceiverOperand());
|
||||||
@ -213,9 +213,8 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
|
|
||||||
// Copy any necessary parameters into the context.
|
// Copy any necessary parameters into the context.
|
||||||
int num_parameters = scope()->num_parameters();
|
int num_parameters = scope()->num_parameters();
|
||||||
int first_parameter = scope()->has_this_declaration() ? -1 : 0;
|
for (int i = 0; i < num_parameters; i++) {
|
||||||
for (int i = first_parameter; i < num_parameters; i++) {
|
Variable* var = scope()->parameter(i);
|
||||||
Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
|
|
||||||
if (var->IsContextSlot()) {
|
if (var->IsContextSlot()) {
|
||||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||||
(num_parameters - 1 - i) * kPointerSize;
|
(num_parameters - 1 - i) * kPointerSize;
|
||||||
|
@ -962,6 +962,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
THIS = 1 << 2,
|
THIS = 1 << 2,
|
||||||
INNER_ARGUMENTS = 1 << 3,
|
INNER_ARGUMENTS = 1 << 3,
|
||||||
INNER_SUPER_PROPERTY = 1 << 4,
|
INNER_SUPER_PROPERTY = 1 << 4,
|
||||||
|
INNER_THIS = 1 << 5
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@ -976,7 +977,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
{"return this + arguments[0]", ARGUMENTS | THIS},
|
{"return this + arguments[0]", ARGUMENTS | THIS},
|
||||||
{"return this + arguments[0] + super.x",
|
{"return this + arguments[0] + super.x",
|
||||||
ARGUMENTS | SUPER_PROPERTY | THIS},
|
ARGUMENTS | SUPER_PROPERTY | THIS},
|
||||||
{"return x => this + x", THIS},
|
{"return x => this + x", INNER_THIS},
|
||||||
{"return x => super.f() + x", INNER_SUPER_PROPERTY},
|
{"return x => super.f() + x", INNER_SUPER_PROPERTY},
|
||||||
{"this.foo = 42;", THIS},
|
{"this.foo = 42;", THIS},
|
||||||
{"this.foo();", THIS},
|
{"this.foo();", THIS},
|
||||||
@ -990,7 +991,9 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
{"while (true) { while (true) { while (true) return this } }", THIS},
|
{"while (true) { while (true) { while (true) return this } }", THIS},
|
||||||
{"while (true) { while (true) { while (true) return super.f() } }",
|
{"while (true) { while (true) { while (true) return super.f() } }",
|
||||||
SUPER_PROPERTY},
|
SUPER_PROPERTY},
|
||||||
{"if (1) { return () => { while (true) new this() } }", THIS},
|
{"if (1) { return () => { while (true) new this() } }", INNER_THIS},
|
||||||
|
// Note that propagation of the inner_uses_this() value does not
|
||||||
|
// cross boundaries of normal functions onto parent scopes.
|
||||||
{"return function (x) { return this + x }", NONE},
|
{"return function (x) { return this + x }", NONE},
|
||||||
{"return { m(x) { return super.m() + x } }", NONE},
|
{"return { m(x) { return super.m() + x } }", NONE},
|
||||||
{"var x = function () { this.foo = 42 };", NONE},
|
{"var x = function () { this.foo = 42 };", NONE},
|
||||||
@ -1001,10 +1004,10 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
{"return { m(x) { return () => super.m() } }", NONE},
|
{"return { m(x) { return () => super.m() } }", NONE},
|
||||||
// Flags must be correctly set when using block scoping.
|
// Flags must be correctly set when using block scoping.
|
||||||
{"\"use strict\"; while (true) { let x; this, arguments; }",
|
{"\"use strict\"; while (true) { let x; this, arguments; }",
|
||||||
INNER_ARGUMENTS | THIS},
|
INNER_ARGUMENTS | INNER_THIS},
|
||||||
{"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
|
{"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
|
||||||
INNER_ARGUMENTS | INNER_SUPER_PROPERTY | THIS},
|
INNER_ARGUMENTS | INNER_SUPER_PROPERTY | INNER_THIS},
|
||||||
{"\"use strict\"; if (foo()) { let x; this.f() }", THIS},
|
{"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
|
||||||
{"\"use strict\"; if (foo()) { let x; super.f() }",
|
{"\"use strict\"; if (foo()) { let x; super.f() }",
|
||||||
INNER_SUPER_PROPERTY},
|
INNER_SUPER_PROPERTY},
|
||||||
{"\"use strict\"; if (1) {"
|
{"\"use strict\"; if (1) {"
|
||||||
@ -1068,15 +1071,13 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
scope->uses_arguments());
|
scope->uses_arguments());
|
||||||
CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
|
CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
|
||||||
scope->uses_super_property());
|
scope->uses_super_property());
|
||||||
if ((source_data[i].expected & THIS) != 0) {
|
CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
|
||||||
// Currently the is_used() flag is conservative; all variables in a
|
|
||||||
// script scope are marked as used.
|
|
||||||
CHECK(scope->LookupThis()->is_used());
|
|
||||||
}
|
|
||||||
CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
|
CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
|
||||||
scope->inner_uses_arguments());
|
scope->inner_uses_arguments());
|
||||||
CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
|
CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
|
||||||
scope->inner_uses_super_property());
|
scope->inner_uses_super_property());
|
||||||
|
CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
|
||||||
|
scope->inner_uses_this());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -628,7 +628,7 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization,
|
|||||||
root =
|
root =
|
||||||
deserializer.DeserializePartial(isolate, global_proxy,
|
deserializer.DeserializePartial(isolate, global_proxy,
|
||||||
&outdated_contexts).ToHandleChecked();
|
&outdated_contexts).ToHandleChecked();
|
||||||
CHECK_EQ(3, outdated_contexts->length());
|
CHECK_EQ(2, outdated_contexts->length());
|
||||||
CHECK(root->IsContext());
|
CHECK(root->IsContext());
|
||||||
Handle<Context> context = Handle<Context>::cast(root);
|
Handle<Context> context = Handle<Context>::cast(root);
|
||||||
CHECK(context->global_proxy() == *global_proxy);
|
CHECK(context->global_proxy() == *global_proxy);
|
||||||
|
@ -167,10 +167,6 @@ function CheckScopeContent(content, number, exec_state) {
|
|||||||
if (!scope.scopeObject().property('arguments').isUndefined()) {
|
if (!scope.scopeObject().property('arguments').isUndefined()) {
|
||||||
scope_size--;
|
scope_size--;
|
||||||
}
|
}
|
||||||
// Ditto for 'this'.
|
|
||||||
if (!scope.scopeObject().property('this').isUndefined()) {
|
|
||||||
scope_size--;
|
|
||||||
}
|
|
||||||
// Skip property with empty name.
|
// Skip property with empty name.
|
||||||
if (!scope.scopeObject().property('').isUndefined()) {
|
if (!scope.scopeObject().property('').isUndefined()) {
|
||||||
scope_size--;
|
scope_size--;
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
// Copyright 2015 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-arrow-functions
|
|
||||||
|
|
||||||
var object = {};
|
|
||||||
var global = this;
|
|
||||||
var call = Function.call.bind(Function.call);
|
|
||||||
|
|
||||||
var globalSloppyArrow = () => this;
|
|
||||||
var globalStrictArrow = () => { "use strict"; return this; };
|
|
||||||
var globalSloppyArrowEval = (s) => eval(s);
|
|
||||||
var globalStrictArrowEval = (s) => { "use strict"; return eval(s); };
|
|
||||||
|
|
||||||
var sloppyFunctionArrow = function() {
|
|
||||||
return (() => this)();
|
|
||||||
};
|
|
||||||
var strictFunctionArrow = function() {
|
|
||||||
"use strict";
|
|
||||||
return (() => this)();
|
|
||||||
};
|
|
||||||
var sloppyFunctionEvalArrow = function() {
|
|
||||||
return eval("(() => this)()");
|
|
||||||
};
|
|
||||||
var strictFunctionEvalArrow = function() {
|
|
||||||
"use strict";
|
|
||||||
return eval("(() => this)()");
|
|
||||||
};
|
|
||||||
var sloppyFunctionArrowEval = function(s) {
|
|
||||||
return (() => eval(s))();
|
|
||||||
};
|
|
||||||
var strictFunctionArrowEval = function(s) {
|
|
||||||
"use strict";
|
|
||||||
return (() => eval(s))();
|
|
||||||
};
|
|
||||||
|
|
||||||
var withObject = { 'this': object }
|
|
||||||
var arrowInsideWith, arrowInsideWithEval;
|
|
||||||
with (withObject) {
|
|
||||||
arrowInsideWith = () => this;
|
|
||||||
arrowInsideWithEval = (s) => eval(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(global, call(globalSloppyArrow, object));
|
|
||||||
assertEquals(global, call(globalStrictArrow, object));
|
|
||||||
assertEquals(global, call(globalSloppyArrowEval, object, "this"));
|
|
||||||
assertEquals(global, call(globalStrictArrowEval, object, "this"));
|
|
||||||
assertEquals(global, call(globalSloppyArrowEval, object, "(() => this)()"));
|
|
||||||
assertEquals(global, call(globalStrictArrowEval, object, "(() => this)()"));
|
|
||||||
|
|
||||||
assertEquals(object, call(sloppyFunctionArrow, object));
|
|
||||||
assertEquals(global, call(sloppyFunctionArrow, undefined));
|
|
||||||
assertEquals(object, call(strictFunctionArrow, object));
|
|
||||||
assertEquals(undefined, call(strictFunctionArrow, undefined));
|
|
||||||
|
|
||||||
assertEquals(object, call(sloppyFunctionEvalArrow, object));
|
|
||||||
assertEquals(global, call(sloppyFunctionEvalArrow, undefined));
|
|
||||||
assertEquals(object, call(strictFunctionEvalArrow, object));
|
|
||||||
assertEquals(undefined, call(strictFunctionEvalArrow, undefined));
|
|
||||||
|
|
||||||
assertEquals(object, call(sloppyFunctionArrowEval, object, "this"));
|
|
||||||
assertEquals(global, call(sloppyFunctionArrowEval, undefined, "this"));
|
|
||||||
assertEquals(object, call(strictFunctionArrowEval, object, "this"));
|
|
||||||
assertEquals(undefined, call(strictFunctionArrowEval, undefined, "this"));
|
|
||||||
|
|
||||||
assertEquals(object,
|
|
||||||
call(sloppyFunctionArrowEval, object, "(() => this)()"));
|
|
||||||
assertEquals(global,
|
|
||||||
call(sloppyFunctionArrowEval, undefined, "(() => this)()"));
|
|
||||||
assertEquals(object,
|
|
||||||
call(strictFunctionArrowEval, object, "(() => this)()"));
|
|
||||||
assertEquals(undefined,
|
|
||||||
call(strictFunctionArrowEval, undefined, "(() => this)()"));
|
|
||||||
|
|
||||||
assertEquals(global, call(arrowInsideWith, undefined));
|
|
||||||
assertEquals(global, call(arrowInsideWith, object));
|
|
||||||
assertEquals(global, call(arrowInsideWithEval, undefined, "this"));
|
|
||||||
assertEquals(global, call(arrowInsideWithEval, object, "this"));
|
|
||||||
assertEquals(global, call(arrowInsideWithEval, undefined, "(() => this)()"));
|
|
||||||
assertEquals(global, call(arrowInsideWithEval, object, "(() => this)()"));
|
|
@ -35,7 +35,6 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
|
|||||||
FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
|
FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
|
||||||
SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME")
|
SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME")
|
||||||
MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE)
|
MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE)
|
||||||
NO_HARNESS_PATTERN = re.compile(r"^// NO HARNESS$", flags=re.MULTILINE)
|
|
||||||
|
|
||||||
|
|
||||||
class MjsunitTestSuite(testsuite.TestSuite):
|
class MjsunitTestSuite(testsuite.TestSuite):
|
||||||
@ -80,7 +79,7 @@ class MjsunitTestSuite(testsuite.TestSuite):
|
|||||||
env = ["-e", "TEST_FILE_NAME=\"%s\"" % testfilename.replace("\\", "\\\\")]
|
env = ["-e", "TEST_FILE_NAME=\"%s\"" % testfilename.replace("\\", "\\\\")]
|
||||||
files = env + files
|
files = env + files
|
||||||
|
|
||||||
if not context.no_harness and not NO_HARNESS_PATTERN.search(source):
|
if not context.no_harness:
|
||||||
files.append(os.path.join(self.root, "mjsunit.js"))
|
files.append(os.path.join(self.root, "mjsunit.js"))
|
||||||
|
|
||||||
if MODULE_PATTERN.search(source):
|
if MODULE_PATTERN.search(source):
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
// Copyright 2015 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-arrow-functions
|
|
||||||
// NO HARNESS
|
|
||||||
|
|
||||||
var globalEval = eval;
|
|
||||||
globalEval("this; eval('42')");
|
|
||||||
globalEval("eval('42'); this");
|
|
Loading…
Reference in New Issue
Block a user