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:
Michael Starzinger 2014-11-13 11:48:22 +01:00
parent 910711a169
commit 9e0865069f
8 changed files with 56 additions and 92 deletions

View File

@ -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(

View File

@ -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();

View File

@ -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()) {

View File

@ -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);

View File

@ -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(

View File

@ -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(

View File

@ -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(

View File

@ -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;
}