Perform receiver patching for sloppy mode in high-level IR.
R=verwaest@chromium.org TEST=cctest/test-run-jscalls/ReceiverPatching Review URL: https://codereview.chromium.org/717093002 Cr-Commit-Position: refs/heads/master@{#25322}
This commit is contained in:
parent
910711a169
commit
9e0865069f
@ -738,24 +738,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ Prologue(info->IsCodePreAgingActive());
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
if (info->strict_mode() == SLOPPY && !info->is_native()) {
|
||||
Label ok;
|
||||
// +2 for return address and saved frame pointer.
|
||||
int receiver_slot = info->scope()->num_parameters() + 2;
|
||||
__ ldr(r2, MemOperand(fp, receiver_slot * kPointerSize));
|
||||
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ b(ne, &ok);
|
||||
__ ldr(r2, GlobalObjectOperand());
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalProxyOffset));
|
||||
__ str(r2, MemOperand(fp, receiver_slot * kPointerSize));
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
} else {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
|
@ -802,23 +802,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ Prologue(info->IsCodePreAgingActive());
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
if (info->strict_mode() == SLOPPY && !info->is_native()) {
|
||||
Label ok;
|
||||
// +2 for return address and saved frame pointer.
|
||||
int receiver_slot = info->scope()->num_parameters() + 2;
|
||||
__ Ldr(x10, MemOperand(fp, receiver_slot * kXRegSize));
|
||||
__ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
|
||||
__ Ldr(x10, GlobalObjectMemOperand());
|
||||
__ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
|
||||
__ Str(x10, MemOperand(fp, receiver_slot * kXRegSize));
|
||||
__ Bind(&ok);
|
||||
}
|
||||
|
||||
} else {
|
||||
__ SetStackPointer(jssp);
|
||||
__ StubPrologue();
|
||||
|
@ -72,13 +72,22 @@ bool AstGraphBuilder::CreateGraph() {
|
||||
Environment env(this, scope, graph()->start());
|
||||
set_environment(&env);
|
||||
|
||||
// Initialize the incoming context.
|
||||
Node* outer_context = GetFunctionContext();
|
||||
set_current_context(outer_context);
|
||||
|
||||
// Build receiver check for sloppy mode if necessary.
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
Node* original_receiver = env.Lookup(scope->receiver());
|
||||
Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
|
||||
env.Bind(scope->receiver(), patched_receiver);
|
||||
|
||||
// Build node to initialize local function context.
|
||||
Node* closure = GetFunctionClosure();
|
||||
Node* outer = GetFunctionContext();
|
||||
Node* inner = BuildLocalFunctionContext(outer, closure);
|
||||
Node* inner_context = BuildLocalFunctionContext(outer_context, closure);
|
||||
|
||||
// Push top-level function scope for the function body.
|
||||
ContextScope top_context(this, scope, inner);
|
||||
ContextScope top_context(this, scope, inner_context);
|
||||
|
||||
// Build the arguments object if it is used.
|
||||
BuildArgumentsObject(scope->arguments());
|
||||
@ -1773,10 +1782,36 @@ Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object). Otherwise there is nothing left to do here.
|
||||
if (info()->strict_mode() != SLOPPY || info()->is_native()) return receiver;
|
||||
|
||||
// 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()->scope()->uses_this() && !info()->scope()->inner_uses_this() &&
|
||||
!info()->scope()->calls_sloppy_eval()) {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
IfBuilder receiver_check(this);
|
||||
Node* undefined = jsgraph()->UndefinedConstant();
|
||||
Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
|
||||
receiver_check.If(check);
|
||||
receiver_check.Then();
|
||||
environment()->Push(BuildLoadGlobalProxy());
|
||||
receiver_check.Else();
|
||||
environment()->Push(receiver);
|
||||
receiver_check.End();
|
||||
return environment()->Pop();
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
|
||||
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
||||
if (heap_slots <= 0) return context;
|
||||
set_current_context(context);
|
||||
|
||||
// Allocate a new local context.
|
||||
const Operator* op = javascript()->CreateFunctionContext();
|
||||
@ -2069,6 +2104,14 @@ Node* AstGraphBuilder::BuildLoadGlobalObject() {
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildLoadGlobalProxy() {
|
||||
Node* global = BuildLoadGlobalObject();
|
||||
Node* proxy =
|
||||
BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildToBoolean(Node* input) {
|
||||
// TODO(titzer): this should be in a JSOperatorReducer.
|
||||
switch (input->opcode()) {
|
||||
|
@ -72,6 +72,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
|
||||
// other dependencies tracked by the environment might be mutated though.
|
||||
//
|
||||
|
||||
// Builder to create a receiver check for sloppy mode.
|
||||
Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
|
||||
|
||||
// Builder to create a local function context.
|
||||
Node* BuildLocalFunctionContext(Node* context, Node* closure);
|
||||
|
||||
@ -92,6 +95,7 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
|
||||
// Builders for accessing the function context.
|
||||
Node* BuildLoadBuiltinsObject();
|
||||
Node* BuildLoadGlobalObject();
|
||||
Node* BuildLoadGlobalProxy();
|
||||
Node* BuildLoadClosure();
|
||||
Node* BuildLoadObjectField(Node* object, int offset);
|
||||
|
||||
|
@ -818,24 +818,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ Prologue(info->IsCodePreAgingActive());
|
||||
frame->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
if (info->strict_mode() == SLOPPY && !info->is_native()) {
|
||||
Label ok;
|
||||
// +2 for return address and saved frame pointer.
|
||||
int receiver_slot = info->scope()->num_parameters() + 2;
|
||||
__ mov(ecx, Operand(ebp, receiver_slot * kPointerSize));
|
||||
__ cmp(ecx, isolate()->factory()->undefined_value());
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
__ mov(ecx, GlobalObjectOperand());
|
||||
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
|
||||
__ mov(Operand(ebp, receiver_slot * kPointerSize), ecx);
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
} else {
|
||||
__ StubPrologue();
|
||||
frame->SetRegisterSaveAreaSize(
|
||||
|
@ -715,24 +715,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ Prologue(info->IsCodePreAgingActive());
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
if (info->strict_mode() == SLOPPY && !info->is_native()) {
|
||||
Label ok;
|
||||
// +2 for return address and saved frame pointer.
|
||||
int receiver_slot = info->scope()->num_parameters() + 2;
|
||||
__ lw(a2, MemOperand(fp, receiver_slot * kPointerSize));
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(&ok, ne, a2, Operand(at));
|
||||
|
||||
__ lw(a2, GlobalObjectOperand());
|
||||
__ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset));
|
||||
__ sw(a2, MemOperand(fp, receiver_slot * kPointerSize));
|
||||
__ bind(&ok);
|
||||
}
|
||||
} else {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
|
@ -799,23 +799,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ Prologue(info->IsCodePreAgingActive());
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
|
||||
// Sloppy mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
|
||||
if (info->strict_mode() == SLOPPY && !info->is_native()) {
|
||||
Label ok;
|
||||
StackArgumentsAccessor args(rbp, info->scope()->num_parameters());
|
||||
__ movp(rcx, args.GetReceiverOperand());
|
||||
__ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
__ movp(rcx, GlobalObjectOperand());
|
||||
__ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
|
||||
__ movp(args.GetReceiverOperand(), rcx);
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
} else {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
|
@ -373,6 +373,11 @@ Scope* Scope::FinalizeBlockScope() {
|
||||
outer_scope()->unresolved_.Add(unresolved_[i], zone());
|
||||
}
|
||||
|
||||
// Propagate usage flags to outer scope.
|
||||
if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
|
||||
if (uses_super()) outer_scope_->RecordSuperUsage();
|
||||
if (uses_this()) outer_scope_->RecordThisUsage();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user