Add script context with context-allocated "const this"
authorwingo <wingo@igalia.com>
Fri, 12 Jun 2015 09:35:50 +0000 (02:35 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 12 Jun 2015 09:35:57 +0000 (09:35 +0000)
R=rossberg@chromium.org
LOG=N
BUG=498811

Review URL: https://codereview.chromium.org/1179893002

Cr-Commit-Position: refs/heads/master@{#28988}

19 files changed:
src/arm/full-codegen-arm.cc
src/arm64/full-codegen-arm64.cc
src/bootstrapper.cc
src/compiler/ast-graph-builder.cc
src/hydrogen.cc
src/ia32/full-codegen-ia32.cc
src/mips/full-codegen-mips.cc
src/mips64/full-codegen-mips64.cc
src/objects.h
src/ppc/full-codegen-ppc.cc
src/runtime/runtime-compiler.cc
src/runtime/runtime.h
src/scopeinfo.cc
src/scopes.h
src/snapshot/snapshot-common.cc
src/variables.h
src/x64/full-codegen-x64.cc
src/x87/full-codegen-x87.cc
test/unittests/compiler/js-type-feedback-unittest.cc

index 9a01faddc1f42738518b1dcac7b70d6d8f04562b..a2f24400a4fc53612d0b5123f618266a89f75bfb 100644 (file)
@@ -3104,20 +3104,15 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
 
 
 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
-  // r5: copy of the first argument or undefined if it doesn't exist.
+  // r4: copy of the first argument or undefined if it doesn't exist.
   if (arg_count > 0) {
-    __ ldr(r5, MemOperand(sp, arg_count * kPointerSize));
+    __ ldr(r4, MemOperand(sp, arg_count * kPointerSize));
   } else {
-    __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+    __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
   }
 
-  // r4: the receiver of the enclosing function.
-  __ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-
   // r3: the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ ldr(r3, VarOperand(this_var, r3));
+  __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
   // r2: language mode.
   __ mov(r2, Operand(Smi::FromInt(language_mode())));
@@ -3126,9 +3121,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
 
   // Do the runtime call.
-  __ Push(r5);
   __ Push(r4, r3, r2, r1);
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3160,10 +3154,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
   Call::CallType call_type = expr->GetCallType(isolate());
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
-    // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the
-    // call.  Then we call the resolved function using the given
-    // arguments.
+    // In a call to eval, we first call
+    // RuntimeHidden_asResolvePossiblyDirectEval to resolve the function we need
+    // to call.  Then we call the resolved function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
 
@@ -3183,10 +3176,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(r1);
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in r0 (function) and
-      // r1 (receiver). Touch up the stack with the right values.
+      // Touch up the stack with the resolved function.
       __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
-      __ str(r1, MemOperand(sp, arg_count * kPointerSize));
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
@@ -4783,9 +4774,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(r0);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ ldr(r2, GlobalObjectOperand());
           __ mov(r1, Operand(var->name()));
@@ -4796,7 +4788,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
           // Result of deleting non-global, non-dynamic variables is false.
           // The subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 90b57784d9eb75708bd45229ee63f3874c0ef067..454bf03ddcbd2862c1ea02a5edc63437c020e3fa 100644 (file)
@@ -2799,21 +2799,17 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   }
 
   __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-  // Prepare to push the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ Ldr(x11, VarOperand(this_var, x11));
 
   // Prepare to push the language mode.
-  __ Mov(x12, Smi::FromInt(language_mode()));
+  __ Mov(x11, Smi::FromInt(language_mode()));
   // Prepare to push the start position of the scope the calls resides in.
-  __ Mov(x13, Smi::FromInt(scope()->start_position()));
+  __ Mov(x12, Smi::FromInt(scope()->start_position()));
 
   // Push.
-  __ Push(x9, x10, x11, x12, x13);
+  __ Push(x9, x10, x11, x12);
 
   // Do the runtime call.
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -2845,9 +2841,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the
-    // call.  Then we call the resolved function using the given
-    // arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
 
@@ -2868,9 +2863,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ Push(x10);
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in x0 (function) and
-      // x1 (receiver). Touch up the stack with the right values.
-      __ PokePair(x1, x0, arg_count * kPointerSize);
+      // Touch up the stack with the resolved function.
+      __ Poke(x0, (arg_count + 1) * kPointerSize);
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
@@ -4464,9 +4458,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(x0);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ Ldr(x12, GlobalObjectMemOperand());
           __ Mov(x11, Operand(var->name()));
@@ -4477,7 +4472,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
           // Result of deleting non-global, non-dynamic variables is false.
           // The subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index c675fe7e0d423211669c505a2f1a7a4169a9aa31..73dd2989a79d997cdfe20a48bd1a8e020d02a2ba 100644 (file)
@@ -197,6 +197,11 @@ class Genesis BASE_EMBEDDED {
   // other objects in the snapshot.
   void HookUpGlobalObject(Handle<GlobalObject> global_object,
                           Handle<FixedArray> outdated_contexts);
+  // The native context has a ScriptContextTable that store declarative bindings
+  // made in script scopes.  Add a "this" binding to that table pointing to the
+  // global proxy.
+  void InstallGlobalThisBinding();
+  void HookUpGlobalThisBinding(Handle<FixedArray> outdated_contexts);
   // New context initialization.  Used for creating a context from scratch.
   void InitializeGlobal(Handle<GlobalObject> global_object,
                         Handle<JSFunction> empty_function);
@@ -814,6 +819,40 @@ void Genesis::CreateRoots() {
 }
 
 
+void Genesis::InstallGlobalThisBinding() {
+  Handle<ScriptContextTable> script_contexts(
+      native_context()->script_context_table());
+  Handle<ScopeInfo> scope_info = ScopeInfo::CreateGlobalThisBinding(isolate());
+  Handle<JSFunction> closure(native_context()->closure());
+  Handle<Context> context = factory()->NewScriptContext(closure, scope_info);
+
+  // Go ahead and hook it up while we're at it.
+  int slot = scope_info->ReceiverContextSlotIndex();
+  DCHECK_EQ(slot, Context::MIN_CONTEXT_SLOTS);
+  context->set(slot, native_context()->global_proxy());
+
+  native_context()->set_script_context_table(
+      *ScriptContextTable::Extend(script_contexts, context));
+}
+
+
+void Genesis::HookUpGlobalThisBinding(Handle<FixedArray> outdated_contexts) {
+  // One of these contexts should be the one that declares the global "this"
+  // binding.
+  for (int i = 0; i < outdated_contexts->length(); ++i) {
+    Context* context = Context::cast(outdated_contexts->get(i));
+    if (context->IsScriptContext()) {
+      ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
+      int slot = scope_info->ReceiverContextSlotIndex();
+      if (slot >= 0) {
+        DCHECK_EQ(slot, Context::MIN_CONTEXT_SLOTS);
+        context->set(slot, native_context()->global_proxy());
+      }
+    }
+  }
+}
+
+
 Handle<GlobalObject> Genesis::CreateNewGlobals(
     v8::Handle<v8::ObjectTemplate> global_proxy_template,
     Handle<JSGlobalProxy> global_proxy) {
@@ -972,6 +1011,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
   Handle<ScriptContextTable> script_context_table =
       factory->NewScriptContextTable();
   native_context()->set_script_context_table(*script_context_table);
+  InstallGlobalThisBinding();
 
   Handle<String> object_name = factory->Object_string();
   JSObject::AddProperty(
@@ -3086,6 +3126,7 @@ Genesis::Genesis(Isolate* isolate,
     HookUpGlobalObject(global_object, outdated_contexts);
     native_context()->builtins()->set_global_proxy(
         native_context()->global_proxy());
+    HookUpGlobalThisBinding(outdated_contexts);
 
     if (!ConfigureGlobalObjects(global_proxy_template)) return;
   } else {
index 43d402094539cfae9c31dd3f2f3395888a17db86..cf7bbc99a52a8e830c5b3b5d78fd6e8635649402 100644 (file)
@@ -2420,37 +2420,17 @@ void AstGraphBuilder::VisitCall(Call* expr) {
     // Create node to ask for help resolving potential eval call. This will
     // provide a fully resolved callee and the corresponding receiver.
     Node* function = GetFunctionClosure();
-    // TODO(wingo): ResolvePossibleDirectEval doesn't really need a 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* position = jsgraph()->Constant(current_scope()->start_position());
     const Operator* op =
-        javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
-    Node* pair =
-        NewNode(op, callee, source, function, receiver, language, position);
-    PrepareFrameState(pair, expr->EvalOrLookupId(),
+        javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+    Node* new_callee =
+        NewNode(op, callee, source, function, language, position);
+    PrepareFrameState(new_callee, expr->EvalOrLookupId(),
                       OutputFrameStateCombine::PokeAt(arg_count + 1));
-    Node* new_callee = NewNode(common()->Projection(0), pair);
-    Node* new_receiver = NewNode(common()->Projection(1), pair);
 
-    // Patch callee and receiver on the environment.
+    // Patch callee on the environment.
     environment()->Poke(arg_count + 1, new_callee);
-    environment()->Poke(arg_count + 0, new_receiver);
   }
 
   // Create node to perform the function call.
@@ -2873,7 +2853,9 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
     // Delete of an unqualified identifier is only allowed in classic mode but
     // deleting "this" is allowed in all language modes.
     Variable* variable = expr->expression()->AsVariableProxy()->var();
-    DCHECK(is_sloppy(language_mode()) || variable->is_this());
+    // Delete of an unqualified identifier is disallowed in strict mode but
+    // "delete this" is allowed.
+    DCHECK(is_sloppy(language_mode()) || variable->HasThisName(isolate()));
     value = BuildVariableDelete(variable, expr->id(),
                                 ast_context()->GetStateCombine());
   } else if (expr->expression()->IsProperty()) {
@@ -3321,9 +3303,10 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable,
     }
     case Variable::PARAMETER:
     case Variable::LOCAL:
-    case Variable::CONTEXT:
+    case Variable::CONTEXT: {
       // Local var, const, or let variable or context variable.
-      return jsgraph()->BooleanConstant(variable->is_this());
+      return jsgraph()->BooleanConstant(variable->HasThisName(isolate()));
+    }
     case Variable::LOOKUP: {
       // Dynamic lookup of context variable (anywhere in the chain).
       Node* name = jsgraph()->Constant(variable->name());
index 810a8b92210d4bb2389d024490c65b0b88e22eb1..ecf05f4bc53555367cf1c19c649c6be9d2d0b0d3 100644 (file)
@@ -10197,12 +10197,11 @@ void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
     if (var->IsUnallocated()) {
       Bailout(kDeleteWithGlobalVariable);
     } else if (var->IsStackAllocated() || var->IsContextSlot()) {
-      // Result of deleting non-global variables is false.  'this' is not
-      // really a variable, though we implement it as one.  The
-      // subexpression does not have side effects.
-      HValue* value = var->is_this()
-          ? graph()->GetConstantTrue()
-          : graph()->GetConstantFalse();
+      // Result of deleting non-global variables is false.  'this' is not really
+      // a variable, though we implement it as one.  The subexpression does not
+      // have side effects.
+      HValue* value = var->HasThisName(isolate()) ? graph()->GetConstantTrue()
+                                                  : graph()->GetConstantFalse();
       return ast_context()->ReturnValue(value);
     } else {
       Bailout(kDeleteWithNonGlobalVariable);
index 40d54a6d691dadede991e5ac253e9aa32d025072..202740b385cc93bef3ba8e9a966d8d6a2708f004 100644 (file)
@@ -3006,10 +3006,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
 
   // Push the enclosing function.
   __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-  // Push the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ push(VarOperand(this_var, ecx));
+
   // Push the language mode.
   __ push(Immediate(Smi::FromInt(language_mode())));
 
@@ -3017,7 +3014,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ push(Immediate(Smi::FromInt(scope()->start_position())));
 
   // Do the runtime call.
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3049,8 +3046,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the call.
-    // Then we call the resolved function using the given arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
     { PreservePositionScope pos_scope(masm()->positions_recorder());
@@ -3067,9 +3064,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(Operand(esp, (arg_count + 1) * kPointerSize));
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in eax (function) and
-      // edx (receiver). Touch up the stack with the right values.
-      __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
+      // Touch up the stack with the resolved function.
       __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
@@ -4703,9 +4698,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(eax);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ push(GlobalObjectOperand());
           __ push(Immediate(var->name()));
@@ -4716,7 +4712,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           // Result of deleting non-global variables is false.  'this' is
           // not really a variable, though we implement it as one.  The
           // subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index b7d161193c6ff1ecc693edcf0f1d700a7c5254d5..2440f9838362534dd70a472b133c2670b92824a7 100644 (file)
@@ -3089,21 +3089,15 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   // t2: the receiver of the enclosing function.
   __ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
-  // t1: the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ lw(t1, VarOperand(this_var, t1));
+  // t1: the language mode.
+  __ li(t1, Operand(Smi::FromInt(language_mode())));
 
-  // t0: the language mode.
-  __ li(t0, Operand(Smi::FromInt(language_mode())));
-
-  // a1: the start position of the scope the calls resides in.
-  __ li(a1, Operand(Smi::FromInt(scope()->start_position())));
+  // t0: the start position of the scope the calls resides in.
+  __ li(t0, Operand(Smi::FromInt(scope()->start_position())));
 
   // Do the runtime call.
-  __ Push(t3);
-  __ Push(t2, t1, t0, a1);
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ Push(t3, t2, t1, t0);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3136,9 +3130,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the
-    // call.  Then we call the resolved function using the given
-    // arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
 
@@ -3158,10 +3151,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(a1);
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in v0 (function) and
-      // v1 (receiver). Touch up the stack with the right values.
+      // Touch up the stack with the resolved function.
       __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
-      __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
@@ -4790,9 +4781,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(v0);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ lw(a2, GlobalObjectOperand());
           __ li(a1, Operand(var->name()));
@@ -4803,7 +4795,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
           // Result of deleting non-global, non-dynamic variables is false.
           // The subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 4f5139b129dd9ac39d51a70d7fddb9d7547d35ca..572b5b3a77569a637834ccfff86a49b553da7e04 100644 (file)
@@ -3081,20 +3081,15 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
 
 
 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
-  // a7: copy of the first argument or undefined if it doesn't exist.
+  // a6: copy of the first argument or undefined if it doesn't exist.
   if (arg_count > 0) {
-    __ ld(a7, MemOperand(sp, arg_count * kPointerSize));
+    __ ld(a6, MemOperand(sp, arg_count * kPointerSize));
   } else {
-    __ LoadRoot(a7, Heap::kUndefinedValueRootIndex);
+    __ LoadRoot(a6, Heap::kUndefinedValueRootIndex);
   }
 
-  // a6: the receiver of the enclosing function.
-  __ ld(a6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-
   // a5: the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ ld(a5, VarOperand(this_var, a5));
+  __ ld(a5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
   // a4: the language mode.
   __ li(a4, Operand(Smi::FromInt(language_mode())));
@@ -3103,9 +3098,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ li(a1, Operand(Smi::FromInt(scope()->start_position())));
 
   // Do the runtime call.
-  __ Push(a7);
   __ Push(a6, a5, a4, a1);
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3138,9 +3132,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the
-    // call.  Then we call the resolved function using the given
-    // arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
 
@@ -3160,10 +3153,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(a1);
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in v0 (function) and
-      // v1 (receiver). Touch up the stack with the right values.
+      // Touch up the stack with the resolved function.
       __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
-      __ sd(v1, MemOperand(sp, arg_count * kPointerSize));
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
@@ -4793,9 +4784,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(v0);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ ld(a2, GlobalObjectOperand());
           __ li(a1, Operand(var->name()));
@@ -4806,7 +4798,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
           // Result of deleting non-global, non-dynamic variables is false.
           // The subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 031ec6e10433cfb9c0c4144aa9f9c5687ac145ec..e9c8378332e5c9d83dc1355211d1e47f1796541a 100644 (file)
@@ -4055,6 +4055,7 @@ class ScopeInfo : public FixedArray {
 
 
   static Handle<ScopeInfo> Create(Isolate* isolate, Zone* zone, Scope* scope);
+  static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
 
   // Serializes empty scope info.
   static ScopeInfo* Empty(Isolate* isolate);
index 0145d006488afab0ebd5d46736d6252a01d87756..ebd7efe8fbdb5534631ed245aa7fae530a2f119f 100644 (file)
@@ -3094,20 +3094,15 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
 
 
 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
-  // r8: copy of the first argument or undefined if it doesn't exist.
+  // r7: copy of the first argument or undefined if it doesn't exist.
   if (arg_count > 0) {
-    __ LoadP(r8, MemOperand(sp, arg_count * kPointerSize), r0);
+    __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0);
   } else {
-    __ LoadRoot(r8, Heap::kUndefinedValueRootIndex);
+    __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
   }
 
-  // r7: the receiver of the enclosing function.
-  __ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-
   // r6: the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  GetVar(r6, this_var);
+  __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
   // r5: language mode.
   __ LoadSmiLiteral(r5, Smi::FromInt(language_mode()));
@@ -3116,8 +3111,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ LoadSmiLiteral(r4, Smi::FromInt(scope()->start_position()));
 
   // Do the runtime call.
-  __ Push(r8, r7, r6, r5, r4);
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ Push(r7, r6, r5, r4);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3150,9 +3145,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the
-    // call.  Then we call the resolved function using the given
-    // arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
 
@@ -3173,10 +3167,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(r4);
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in r3 (function) and
-      // r4 (receiver). Touch up the stack with the right values.
+      // Touch up the stack with the resolved function.
       __ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
-      __ StoreP(r4, MemOperand(sp, arg_count * kPointerSize), r0);
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
@@ -4805,9 +4797,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(r3);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ LoadP(r5, GlobalObjectOperand());
           __ mov(r4, Operand(var->name()));
@@ -4818,7 +4811,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
           // Result of deleting non-global, non-dynamic variables is false.
           // The subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 09ac2ab96b22ddb0d33dd24ab899fdaeabf1ad34..ba92faa3fafe1bca55007012429250f266be7555 100644 (file)
@@ -381,11 +381,10 @@ RUNTIME_FUNCTION(Runtime_CompileString) {
 }
 
 
-static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
-                                    Handle<SharedFunctionInfo> outer_info,
-                                    Handle<Object> receiver,
-                                    LanguageMode language_mode,
-                                    int scope_position) {
+static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
+                                 Handle<SharedFunctionInfo> outer_info,
+                                 LanguageMode language_mode,
+                                 int scope_position) {
   Handle<Context> context = Handle<Context>(isolate->context());
   Handle<Context> native_context = Handle<Context>(context->native_context());
 
@@ -399,7 +398,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
     MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
         MessageTemplate::kCodeGenFromStrings, error_message);
     if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
-    return MakePair(isolate->heap()->exception(), NULL);
+    return isolate->heap()->exception();
   }
 
   // Deal with a normal eval call with a string argument. Compile it
@@ -410,14 +409,14 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
       isolate, compiled,
       Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
                                     restriction, scope_position),
-      MakePair(isolate->heap()->exception(), NULL));
-  return MakePair(*compiled, *receiver);
+      isolate->heap()->exception());
+  return *compiled;
 }
 
 
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
+RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
   HandleScope scope(isolate);
-  DCHECK(args.length() == 6);
+  DCHECK(args.length() == 5);
 
   Handle<Object> callee = args.at<Object>(0);
 
@@ -428,17 +427,17 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
   // the first argument without doing anything).
   if (*callee != isolate->native_context()->global_eval_fun() ||
       !args[1]->IsString()) {
-    return MakePair(*callee, isolate->heap()->undefined_value());
+    return *callee;
   }
 
+  DCHECK(args[3]->IsSmi());
+  DCHECK(is_valid_language_mode(args.smi_at(3)));
+  LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
   DCHECK(args[4]->IsSmi());
-  DCHECK(is_valid_language_mode(args.smi_at(4)));
-  LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(4));
-  DCHECK(args[5]->IsSmi());
   Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
                                         isolate);
   return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
-                           args.at<Object>(3), language_mode, args.smi_at(5));
+                           language_mode, args.smi_at(4));
 }
 }  // namespace internal
 }  // namespace v8
index f45ce7d0723de497f95b462f7e4e39f413255fa9..5e87910f7a8a575ed4edff095e921b78eecbf370 100644 (file)
@@ -127,7 +127,8 @@ namespace internal {
   F(NotifyDeoptimized, 1, 1)            \
   F(CompileForOnStackReplacement, 1, 1) \
   F(TryInstallOptimizedCode, 1, 1)      \
-  F(CompileString, 2, 1)
+  F(CompileString, 2, 1)                \
+  F(ResolvePossiblyDirectEval, 5, 1)
 
 
 #define FOR_EACH_INTRINSIC_DATE(F) \
@@ -697,8 +698,7 @@ namespace internal {
 
 #define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
   F(LoadLookupSlot, 2, 2)                 \
-  F(LoadLookupSlotNoReferenceError, 2, 2) \
-  F(ResolvePossiblyDirectEval, 6, 2)
+  F(LoadLookupSlotNoReferenceError, 2, 2)
 
 
 #define FOR_EACH_INTRINSIC_RETURN_OBJECT(F) \
index b819b172c4ad1db78926b0d59dc253d9841de94f..72c36c2665942f0ad9a66a691d342baf791b6008 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/v8.h"
 
+#include "src/bootstrapper.h"
 #include "src/scopeinfo.h"
 #include "src/scopes.h"
 
@@ -192,6 +193,77 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
 }
 
 
+Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
+  DCHECK(isolate->bootstrapper()->IsActive());
+
+  const int stack_local_count = 0;
+  const int context_local_count = 1;
+  const int strong_mode_free_variable_count = 0;
+  const bool simple_parameter_list = true;
+  const VariableAllocationInfo receiver_info = CONTEXT;
+  const VariableAllocationInfo function_name_info = NONE;
+  const VariableMode function_variable_mode = VAR;
+  const bool has_function_name = false;
+  const bool has_receiver = true;
+  const int parameter_count = 0;
+  const int length = kVariablePartIndex + parameter_count +
+                     (1 + stack_local_count) + 2 * context_local_count +
+                     3 * strong_mode_free_variable_count +
+                     (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
+
+  Factory* factory = isolate->factory();
+  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
+
+  // Encode the flags.
+  int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
+              CallsEvalField::encode(false) |
+              LanguageModeField::encode(SLOPPY) |
+              ReceiverVariableField::encode(receiver_info) |
+              FunctionVariableField::encode(function_name_info) |
+              FunctionVariableMode::encode(function_variable_mode) |
+              AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
+              IsSimpleParameterListField::encode(simple_parameter_list) |
+              BlockScopeIsClassScopeField::encode(false) |
+              FunctionKindField::encode(FunctionKind::kNormalFunction);
+  scope_info->SetFlags(flags);
+  scope_info->SetParameterCount(parameter_count);
+  scope_info->SetStackLocalCount(stack_local_count);
+  scope_info->SetContextLocalCount(context_local_count);
+  scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
+
+  int index = kVariablePartIndex;
+  const int first_slot_index = 0;
+  DCHECK(index == scope_info->StackLocalFirstSlotIndex());
+  scope_info->set(index++, Smi::FromInt(first_slot_index));
+  DCHECK(index == scope_info->StackLocalEntriesIndex());
+
+  // Here we add info for context-allocated "this".
+  DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
+  scope_info->set(index++, *isolate->factory()->this_string());
+  DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
+  const uint32_t value = ContextLocalMode::encode(CONST) |
+                         ContextLocalInitFlag::encode(kCreatedInitialized) |
+                         ContextLocalMaybeAssignedFlag::encode(kNotAssigned);
+  scope_info->set(index++, Smi::FromInt(value));
+
+  DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex());
+  DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex());
+
+  // And here we record that this scopeinfo binds a receiver.
+  DCHECK(index == scope_info->ReceiverEntryIndex());
+  const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
+  scope_info->set(index++, Smi::FromInt(receiver_index));
+
+  DCHECK(index == scope_info->FunctionNameEntryIndex());
+
+  DCHECK_EQ(index, scope_info->length());
+  DCHECK_EQ(scope_info->ParameterCount(), 0);
+  DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
+
+  return scope_info;
+}
+
+
 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
 }
index c6baba5e29d07abf52c3b3473349dd16e6a5a7bc..83703716d24e927dfe53a4527b39dde897d3e912 100644 (file)
@@ -355,8 +355,7 @@ class Scope: public ZoneObject {
   // "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();
+    return (is_function_scope() && !is_arrow_scope()) || is_module_scope();
   }
 
   // The variable corresponding to the 'new.target' value.
index 381a83a722a1ad7c0c69978da46f6bc0ea299d8e..89fe8af2eb774d8f72ce88303ca4a7344d4b6f90 100644 (file)
@@ -77,8 +77,9 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
   if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
   CHECK(result->IsContext());
   // If the snapshot does not contain a custom script, we need to update
-  // the global object for exactly one context.
-  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
+  // the global object for exactly two contexts: the builtins context and the
+  // script context that has the global "this" binding.
+  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 2);
   if (FLAG_profile_deserialization) {
     double ms = timer.Elapsed().InMillisecondsF();
     int bytes = context_data.length();
index 0cb50c87e985580c1fd1c7fc5ea9b3fde63f4206..218eefae08e08a0cd937a14e1d158c5b878d1a0c 100644 (file)
@@ -105,6 +105,16 @@ class Variable: public ZoneObject {
   bool is_this() const { return kind_ == THIS; }
   bool is_arguments() const { return kind_ == ARGUMENTS; }
 
+  // For script scopes, the "this" binding is provided by a ScriptContext added
+  // to the global's ScriptContextTable.  This binding might not statically
+  // resolve to a Variable::THIS binding, instead being DYNAMIC_LOCAL.  However
+  // any variable named "this" does indeed refer to a Variable::THIS binding;
+  // the grammar ensures this to be the case.  So wherever a "this" binding
+  // might be provided by the global, use HasThisName instead of is_this().
+  bool HasThisName(Isolate* isolate) const {
+    return is_this() || *name() == *isolate->factory()->this_string();
+  }
+
   ClassVariable* AsClassVariable() {
     DCHECK(is_class());
     return reinterpret_cast<ClassVariable*>(this);
index f06eaa9384e0215b94118436004bbab583774304..ed29faf4ed424d5fa0898ae2a8f48fdc47b3a5a7 100644 (file)
@@ -3004,11 +3004,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   // Push the enclosing function.
   __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
 
-  // Push the receiver of the enclosing function and do runtime call.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ Push(VarOperand(this_var, rcx));
-
   // Push the language mode.
   __ Push(Smi::FromInt(language_mode()));
 
@@ -3016,7 +3011,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ Push(Smi::FromInt(scope()->start_position()));
 
   // Do the runtime call.
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3048,8 +3043,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the call.
-    // Then we call the resolved function using the given arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
     { PreservePositionScope pos_scope(masm()->positions_recorder());
@@ -3066,9 +3061,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in rax (function) and
-      // rdx (receiver). Touch up the stack with the right values.
-      __ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
+      // Touch up the callee.
       __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
@@ -4728,9 +4721,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(rax);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ Push(GlobalObjectOperand());
           __ Push(var->name());
@@ -4741,7 +4735,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           // Result of deleting non-global variables is false.  'this' is
           // not really a variable, though we implement it as one.  The
           // subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 9fbdd03ae0edabea0c190a9be1fbf7bb9908b81b..e2abd9d311181c39cf4e8b17f26aea0c4138bf1d 100644 (file)
@@ -2997,10 +2997,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
 
   // Push the enclosing function.
   __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-  // Push the receiver of the enclosing function.
-  Variable* this_var = scope()->LookupThis();
-  DCHECK_NOT_NULL(this_var);
-  __ push(VarOperand(this_var, ecx));
+
   // Push the language mode.
   __ push(Immediate(Smi::FromInt(language_mode())));
 
@@ -3008,7 +3005,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
   __ push(Immediate(Smi::FromInt(scope()->start_position())));
 
   // Do the runtime call.
-  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
 }
 
 
@@ -3040,8 +3037,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
 
   if (call_type == Call::POSSIBLY_EVAL_CALL) {
     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
-    // to resolve the function we need to call and the receiver of the call.
-    // Then we call the resolved function using the given arguments.
+    // to resolve the function we need to call.  Then we call the resolved
+    // function using the given arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
     { PreservePositionScope pos_scope(masm()->positions_recorder());
@@ -3058,9 +3055,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       __ push(Operand(esp, (arg_count + 1) * kPointerSize));
       EmitResolvePossiblyDirectEval(arg_count);
 
-      // The runtime call returns a pair of values in eax (function) and
-      // edx (receiver). Touch up the stack with the right values.
-      __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
+      // Touch up the stack with the resolved function.
       __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
 
       PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
@@ -4693,9 +4688,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         context()->Plug(eax);
       } else if (proxy != NULL) {
         Variable* var = proxy->var();
-        // Delete of an unqualified identifier is disallowed in strict mode
-        // but "delete this" is allowed.
-        DCHECK(is_sloppy(language_mode()) || var->is_this());
+        // Delete of an unqualified identifier is disallowed in strict mode but
+        // "delete this" is allowed.
+        bool is_this = var->HasThisName(isolate());
+        DCHECK(is_sloppy(language_mode()) || is_this);
         if (var->IsUnallocated()) {
           __ push(GlobalObjectOperand());
           __ push(Immediate(var->name()));
@@ -4706,7 +4702,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           // Result of deleting non-global variables is false.  'this' is
           // not really a variable, though we implement it as one.  The
           // subexpression does not have side effects.
-          context()->Plug(var->is_this());
+          context()->Plug(is_this);
         } else {
           // Non-global variable.  Call the runtime to try to delete from the
           // context where the variable was introduced.
index 7737cfeeed72d68cc03350c47aa70113fe3eb1d8..bb257cb0a5f5ee3085f203a2d8e25951e1eb5235 100644 (file)
@@ -83,7 +83,7 @@ class JSTypeFeedbackTest : public TypedGraphTest {
     Node* context = UndefinedConstant();
 
     Unique<Name> name = Unique<Name>::CreateUninitialized(
-        isolate()->factory()->NewStringFromAsciiChecked(string));
+        isolate()->factory()->InternalizeUtf8String(string));
     const Operator* op = javascript()->LoadNamed(name, feedback);
     Node* load = graph()->NewNode(op, global, vector, context);
     if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {