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())));
__ 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);
}
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();
__ 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);
}
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()));
} 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.
}
__ 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);
}
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();
__ 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);
}
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()));
} 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.
// 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, 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.
// 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()) {
}
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());
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);
// 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, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
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());
__ 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);
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()));
// 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.
// 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);
}
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();
__ 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);
}
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()));
} 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.
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())));
__ 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);
}
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();
__ 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);
}
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()));
} 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.
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) {
- // 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()));
__ 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);
}
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();
__ 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);
}
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()));
} 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.
}
-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());
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
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);
// 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
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) \
#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) \
#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() ||
- is_script_scope();
+ return (is_function_scope() && !is_arrow_scope()) || is_module_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 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();
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, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
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());
__ 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);
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());
// 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.
// 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, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
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());
__ 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);
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()));
// 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.
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) {