void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
- // r4: copy of the first argument or undefined if it doesn't exist.
+ // r5: copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
- __ ldr(r4, MemOperand(sp, arg_count * kPointerSize));
+ __ ldr(r5, MemOperand(sp, arg_count * kPointerSize));
} else {
- __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
+ __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
}
+ // r4: the receiver of the enclosing function.
+ __ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
// r3: the receiver of the enclosing function.
- __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ Variable* this_var = scope()->LookupThis();
+ DCHECK_NOT_NULL(this_var);
+ __ ldr(r3, VarOperand(this_var, r3));
// r2: language mode.
__ mov(r2, Operand(Smi::FromInt(language_mode())));
__ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
+ __ Push(r5);
__ Push(r4, r3, r2, r1);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
Call::CallType call_type = expr->GetCallType(isolate());
if (call_type == Call::POSSIBLY_EVAL_CALL) {
- // 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.
+ // 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.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
__ push(r1);
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // The runtime call returns a pair of values in r0 (function) and
+ // r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ str(r1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name()));
} 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
}
__ 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(x11, Smi::FromInt(language_mode()));
+ __ Mov(x12, Smi::FromInt(language_mode()));
// Prepare to push the start position of the scope the calls resides in.
- __ Mov(x12, Smi::FromInt(scope()->start_position()));
+ __ Mov(x13, Smi::FromInt(scope()->start_position()));
// Push.
- __ Push(x9, x10, x11, x12);
+ __ Push(x9, x10, x11, x12, x13);
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the
+ // call. Then we call the resolved function using the given
+ // arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
__ Push(x10);
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
- __ Poke(x0, (arg_count + 1) * kPointerSize);
+ // 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);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ Ldr(x12, GlobalObjectMemOperand());
__ Mov(x11, Operand(var->name()));
} 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
// 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);
}
-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) {
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(
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 {
// 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, 5);
- Node* new_callee =
- NewNode(op, callee, source, function, language, position);
- PrepareFrameState(new_callee, expr->EvalOrLookupId(),
+ javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+ Node* pair =
+ NewNode(op, callee, source, function, receiver, language, position);
+ PrepareFrameState(pair, 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 on the environment.
+ // Patch callee and receiver on the environment.
environment()->Poke(arg_count + 1, new_callee);
+ environment()->Poke(arg_count + 0, new_receiver);
}
// Create node to perform the function call.
// 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();
- // Delete of an unqualified identifier is disallowed in strict mode but
- // "delete this" is allowed.
- DCHECK(is_sloppy(language_mode()) || variable->HasThisName(isolate()));
+ DCHECK(is_sloppy(language_mode()) || variable->is_this());
value = BuildVariableDelete(variable, expr->id(),
ast_context()->GetStateCombine());
} else if (expr->expression()->IsProperty()) {
}
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->HasThisName(isolate()));
- }
+ return jsgraph()->BooleanConstant(variable->is_this());
case Variable::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
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->HasThisName(isolate()) ? 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->is_this()
+ ? graph()->GetConstantTrue()
+ : graph()->GetConstantFalse();
return ast_context()->ReturnValue(value);
} else {
Bailout(kDeleteWithNonGlobalVariable);
// 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())));
__ push(Immediate(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the 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());
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // 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);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
// 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
// t2: the receiver of the enclosing function.
__ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
- // t1: the language mode.
- __ li(t1, Operand(Smi::FromInt(language_mode())));
+ // t1: the receiver of the enclosing function.
+ Variable* this_var = scope()->LookupThis();
+ DCHECK_NOT_NULL(this_var);
+ __ lw(t1, VarOperand(this_var, t1));
- // t0: the start position of the scope the calls resides in.
- __ li(t0, Operand(Smi::FromInt(scope()->start_position())));
+ // 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())));
// Do the runtime call.
- __ Push(t3, t2, t1, t0);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ Push(t3);
+ __ Push(t2, t1, t0, a1);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the
+ // call. Then we call the resolved function using the given
+ // arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
__ push(a1);
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // The runtime call returns a pair of values in v0 (function) and
+ // v1 (receiver). Touch up the stack with the right values.
__ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ lw(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
} 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
- // a6: copy of the first argument or undefined if it doesn't exist.
+ // a7: copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
- __ ld(a6, MemOperand(sp, arg_count * kPointerSize));
+ __ ld(a7, MemOperand(sp, arg_count * kPointerSize));
} else {
- __ LoadRoot(a6, Heap::kUndefinedValueRootIndex);
+ __ LoadRoot(a7, Heap::kUndefinedValueRootIndex);
}
+ // a6: the receiver of the enclosing function.
+ __ ld(a6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
// a5: the receiver of the enclosing function.
- __ ld(a5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ Variable* this_var = scope()->LookupThis();
+ DCHECK_NOT_NULL(this_var);
+ __ ld(a5, VarOperand(this_var, a5));
// a4: the language mode.
__ li(a4, Operand(Smi::FromInt(language_mode())));
__ li(a1, Operand(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
+ __ Push(a7);
__ Push(a6, a5, a4, a1);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the
+ // call. Then we call the resolved function using the given
+ // arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
__ push(a1);
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // The runtime call returns a pair of values in v0 (function) and
+ // v1 (receiver). Touch up the stack with the right values.
__ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ sd(v1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ ld(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
} 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
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);
void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
- // r7: copy of the first argument or undefined if it doesn't exist.
+ // r8: copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
- __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0);
+ __ LoadP(r8, MemOperand(sp, arg_count * kPointerSize), r0);
} else {
- __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
+ __ LoadRoot(r8, Heap::kUndefinedValueRootIndex);
}
+ // r7: the receiver of the enclosing function.
+ __ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
// r6: the receiver of the enclosing function.
- __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ Variable* this_var = scope()->LookupThis();
+ DCHECK_NOT_NULL(this_var);
+ GetVar(r6, this_var);
// r5: language mode.
__ LoadSmiLiteral(r5, Smi::FromInt(language_mode()));
__ LoadSmiLiteral(r4, Smi::FromInt(scope()->start_position()));
// Do the runtime call.
- __ Push(r7, r6, r5, r4);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ Push(r8, r7, r6, r5, r4);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the
+ // call. Then we call the resolved function using the given
+ // arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
__ push(r4);
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // The runtime call returns a pair of values in r3 (function) and
+ // r4 (receiver). Touch up the stack with the right values.
__ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+ __ StoreP(r4, MemOperand(sp, arg_count * kPointerSize), r0);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ LoadP(r5, GlobalObjectOperand());
__ mov(r4, Operand(var->name()));
} 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
}
-static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
- Handle<SharedFunctionInfo> outer_info,
- LanguageMode language_mode,
- int scope_position) {
+static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
+ Handle<SharedFunctionInfo> outer_info,
+ Handle<Object> receiver,
+ LanguageMode language_mode,
+ int scope_position) {
Handle<Context> context = Handle<Context>(isolate->context());
Handle<Context> native_context = Handle<Context>(context->native_context());
MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
MessageTemplate::kCodeGenFromStrings, error_message);
if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
- return isolate->heap()->exception();
+ return MakePair(isolate->heap()->exception(), NULL);
}
// Deal with a normal eval call with a string argument. Compile it
isolate, compiled,
Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
restriction, scope_position),
- isolate->heap()->exception());
- return *compiled;
+ MakePair(isolate->heap()->exception(), NULL));
+ return MakePair(*compiled, *receiver);
}
-RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
HandleScope scope(isolate);
- DCHECK(args.length() == 5);
+ DCHECK(args.length() == 6);
Handle<Object> callee = args.at<Object>(0);
// the first argument without doing anything).
if (*callee != isolate->native_context()->global_eval_fun() ||
!args[1]->IsString()) {
- return *callee;
+ return MakePair(*callee, isolate->heap()->undefined_value());
}
- 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,
- language_mode, args.smi_at(4));
+ args.at<Object>(3), language_mode, args.smi_at(5));
}
} // namespace internal
} // namespace v8
F(NotifyDeoptimized, 1, 1) \
F(CompileForOnStackReplacement, 1, 1) \
F(TryInstallOptimizedCode, 1, 1) \
- F(CompileString, 2, 1) \
- F(ResolvePossiblyDirectEval, 5, 1)
+ F(CompileString, 2, 1)
#define FOR_EACH_INTRINSIC_DATE(F) \
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
F(LoadLookupSlot, 2, 2) \
- F(LoadLookupSlotNoReferenceError, 2, 2)
+ F(LoadLookupSlotNoReferenceError, 2, 2) \
+ F(ResolvePossiblyDirectEval, 6, 2)
#define FOR_EACH_INTRINSIC_RETURN_OBJECT(F) \
#include "src/v8.h"
-#include "src/bootstrapper.h"
#include "src/scopeinfo.h"
#include "src/scopes.h"
}
-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());
}
// "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();
+ return (is_function_scope() && !is_arrow_scope()) || is_module_scope() ||
+ is_script_scope();
}
// The variable corresponding to the 'new.target' value.
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 two contexts: the builtins context and the
- // script context that has the global "this" binding.
- CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 2);
+ // the global object for exactly one context.
+ CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
int bytes = context_data.length();
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);
// 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()));
__ Push(Smi::FromInt(scope()->start_position()));
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the 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());
__ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the callee.
+ // 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);
__ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ Push(GlobalObjectOperand());
__ Push(var->name());
// 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
// 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())));
__ push(Immediate(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}
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. Then we call the resolved
- // function using the given arguments.
+ // to resolve the function we need to call and the receiver of the 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());
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
+ // 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);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
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.
- bool is_this = var->HasThisName(isolate());
- DCHECK(is_sloppy(language_mode()) || is_this);
+ // Delete of an unqualified identifier is disallowed in strict mode
+ // but "delete this" is allowed.
+ DCHECK(is_sloppy(language_mode()) || var->is_this());
if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
// 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(is_this);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
Node* context = UndefinedConstant();
Unique<Name> name = Unique<Name>::CreateUninitialized(
- isolate()->factory()->InternalizeUtf8String(string));
+ isolate()->factory()->NewStringFromAsciiChecked(string));
const Operator* op = javascript()->LoadNamed(name, feedback);
Node* load = graph()->NewNode(op, global, vector, context);
if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {