Reland 2 ScriptContext CLs

Changing script context handling from bytecode based to metadata on the
function. This fixes the debugger to explicitly check the code rather
than implicitly relying on a NewScriptContext bytecode causing side
effects.

Bug: chromium:1043151
Tbr: ulan@chromium.org
Change-Id: I38c5c04d7c76155e0a055ae6efd57f25986bdb7d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2013117
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65920}
This commit is contained in:
Toon Verwaest 2020-01-22 15:41:11 +01:00 committed by Commit Bot
parent 6f3cf7aaae
commit 36190b91d4
18 changed files with 218 additions and 188 deletions

View File

@ -96,11 +96,9 @@ Object MakeGenericError(Isolate* isolate, BuiltinArguments args,
DCHECK(template_index->IsSmi());
RETURN_RESULT_OR_FAILURE(
isolate, ErrorUtils::MakeGenericError(
isolate, constructor,
MessageTemplateFromInt(Smi::ToInt(*template_index)), arg0,
arg1, arg2, SKIP_NONE));
return *ErrorUtils::MakeGenericError(
isolate, constructor, MessageTemplateFromInt(Smi::ToInt(*template_index)),
arg0, arg1, arg2, SKIP_NONE);
}
} // namespace
@ -130,10 +128,9 @@ BUILTIN(MakeURIError) {
Handle<JSFunction> constructor = isolate->uri_error_function();
Handle<Object> undefined = isolate->factory()->undefined_value();
MessageTemplate template_index = MessageTemplate::kURIMalformed;
RETURN_RESULT_OR_FAILURE(
isolate,
ErrorUtils::MakeGenericError(isolate, constructor, template_index,
undefined, undefined, undefined, SKIP_NONE));
return *ErrorUtils::MakeGenericError(isolate, constructor, template_index,
undefined, undefined, undefined,
SKIP_NONE);
}
} // namespace internal

View File

@ -864,6 +864,8 @@ DebugInfo::SideEffectState DebugEvaluate::FunctionGetSideEffectState(
info->DebugName().ToCString().get());
}
if (info->needs_script_context()) return DebugInfo::kHasSideEffects;
DCHECK(info->is_compiled());
if (info->HasBytecodeArray()) {
// Check bytecodes against whitelist.

View File

@ -157,6 +157,84 @@ Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
UNREACHABLE();
}
MaybeHandle<Context> NewScriptContext(Isolate* isolate,
Handle<JSFunction> function) {
SaveAndSwitchContext save(isolate, function->context());
SharedFunctionInfo sfi = function->shared();
Handle<Script> script(Script::cast(sfi.script()), isolate);
Handle<ScopeInfo> scope_info(sfi.scope_info(), isolate);
Handle<NativeContext> native_context(NativeContext::cast(function->context()),
isolate);
Handle<JSGlobalObject> global_object(native_context->global_object(),
isolate);
Handle<ScriptContextTable> script_context(
native_context->script_context_table(), isolate);
// Find name clashes.
for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
Handle<String> name(scope_info->ContextLocalName(var), isolate);
VariableMode mode = scope_info->ContextLocalMode(var);
ScriptContextTable::LookupResult lookup;
if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
Handle<Context> context = ScriptContextTable::GetContext(
isolate, script_context, lookup.context_index);
// If we are trying to re-declare a REPL-mode let as a let, allow it.
if (!(mode == VariableMode::kLet && lookup.mode == VariableMode::kLet &&
scope_info->IsReplModeScope() &&
context->scope_info().IsReplModeScope())) {
// ES#sec-globaldeclarationinstantiation 5.b:
// If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
// exception.
MessageLocation location(script, 0, 1);
isolate->ThrowAt(isolate->factory()->NewSyntaxError(
MessageTemplate::kVarRedeclaration, name),
&location);
return MaybeHandle<Context>();
}
}
}
if (IsLexicalVariableMode(mode)) {
LookupIterator it(isolate, global_object, name, global_object,
LookupIterator::OWN_SKIP_INTERCEPTOR);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
// Can't fail since the we looking up own properties on the global object
// skipping interceptors.
CHECK(!maybe.IsNothing());
if ((maybe.FromJust() & DONT_DELETE) != 0) {
// ES#sec-globaldeclarationinstantiation 5.a:
// If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
// exception.
// ES#sec-globaldeclarationinstantiation 5.d:
// If hasRestrictedGlobal is true, throw a SyntaxError exception.
MessageLocation location(script, 0, 1);
isolate->ThrowAt(isolate->factory()->NewSyntaxError(
MessageTemplate::kVarRedeclaration, name),
&location);
return MaybeHandle<Context>();
}
JSGlobalObject::InvalidatePropertyCell(global_object, name);
}
}
Handle<Context> result =
isolate->factory()->NewScriptContext(native_context, scope_info);
int header = scope_info->ContextHeaderLength();
for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
if (scope_info->ContextLocalInitFlag(var) == kNeedsInitialization) {
result->set(header + var, ReadOnlyRoots(isolate).the_hole_value());
}
}
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context, result);
native_context->set_script_context_table(*new_script_context_table);
return result;
}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
const InvokeParams& params) {
RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kInvoke);
@ -206,6 +284,22 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
}
return value;
}
// Set up a ScriptContext when running scripts that need it.
if (function->shared().needs_script_context()) {
Handle<Context> context;
if (!NewScriptContext(isolate, function).ToHandle(&context)) {
if (params.message_handling == Execution::MessageHandling::kReport) {
isolate->ReportPendingMessages();
}
return MaybeHandle<Object>();
}
// We mutate the context if we allocate a script context. This is
// guaranteed to only happen once in a native context since scripts will
// always produce name clashes with themselves.
function->set_context(*context);
}
}
// Entering JavaScript.

View File

@ -1342,6 +1342,30 @@ Object Isolate::StackOverflow() {
return ReadOnlyRoots(heap()).exception();
}
void Isolate::ThrowAt(Handle<JSObject> exception, MessageLocation* location) {
Handle<Name> key_start_pos = factory()->error_start_pos_symbol();
Object::SetProperty(this, exception, key_start_pos,
handle(Smi::FromInt(location->start_pos()), this),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Handle<Name> key_end_pos = factory()->error_end_pos_symbol();
Object::SetProperty(this, exception, key_end_pos,
handle(Smi::FromInt(location->end_pos()), this),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Handle<Name> key_script = factory()->error_script_symbol();
Object::SetProperty(this, exception, key_script, location->script(),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Throw(*exception, location);
}
Object Isolate::TerminateExecution() {
return Throw(ReadOnlyRoots(this).termination_exception(), nullptr);
}

View File

@ -772,6 +772,8 @@ class Isolate final : private HiddenFactory {
return MaybeHandle<T>();
}
void ThrowAt(Handle<JSObject> exception, MessageLocation* location);
void set_console_delegate(debug::ConsoleDelegate* delegate) {
console_delegate_ = delegate;
}

View File

@ -990,7 +990,7 @@ MaybeHandle<String> MessageFormatter::Format(Isolate* isolate,
return builder.Finish();
}
MaybeHandle<Object> ErrorUtils::Construct(
MaybeHandle<JSObject> ErrorUtils::Construct(
Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
StackTraceCollection stack_trace_collection) {
@ -1007,7 +1007,7 @@ MaybeHandle<Object> ErrorUtils::Construct(
ASSIGN_RETURN_ON_EXCEPTION(
isolate, err,
JSObject::New(target, new_target_recv, Handle<AllocationSite>::null()),
Object);
JSObject);
// 3. If message is not undefined, then
// a. Let msg be ? ToString(message).
@ -1019,23 +1019,23 @@ MaybeHandle<Object> ErrorUtils::Construct(
if (!message->IsUndefined(isolate)) {
Handle<String> msg_string;
ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
Object::ToString(isolate, message), Object);
Object::ToString(isolate, message), JSObject);
RETURN_ON_EXCEPTION(
isolate,
JSObject::SetOwnPropertyIgnoreAttributes(
err, isolate->factory()->message_string(), msg_string, DONT_ENUM),
Object);
JSObject);
}
switch (stack_trace_collection) {
case StackTraceCollection::kDetailed:
RETURN_ON_EXCEPTION(
isolate, isolate->CaptureAndSetDetailedStackTrace(err), Object);
isolate, isolate->CaptureAndSetDetailedStackTrace(err), JSObject);
V8_FALLTHROUGH;
case StackTraceCollection::kSimple:
RETURN_ON_EXCEPTION(
isolate, isolate->CaptureAndSetSimpleStackTrace(err, mode, caller),
Object);
JSObject);
break;
case StackTraceCollection::kNone:
break;
@ -1144,7 +1144,7 @@ Handle<String> DoFormatMessage(Isolate* isolate, MessageTemplate index,
} // namespace
// static
MaybeHandle<Object> ErrorUtils::MakeGenericError(
Handle<JSObject> ErrorUtils::MakeGenericError(
Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
FrameSkipMode mode) {
@ -1167,8 +1167,11 @@ MaybeHandle<Object> ErrorUtils::MakeGenericError(
DCHECK(mode != SKIP_UNTIL_SEEN);
Handle<Object> no_caller;
// The call below can't fail because constructor is a builtin.
DCHECK(constructor->shared().HasBuiltinId());
return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode,
no_caller, StackTraceCollection::kDetailed);
no_caller, StackTraceCollection::kDetailed)
.ToHandleChecked();
}
namespace {

View File

@ -269,14 +269,14 @@ class ErrorUtils : public AllStatic {
// |kNone| is useful when you don't need the stack information at all, for
// example when creating a deserialized error.
enum class StackTraceCollection { kDetailed, kSimple, kNone };
static MaybeHandle<Object> Construct(
static MaybeHandle<JSObject> Construct(
Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
StackTraceCollection stack_trace_collection);
static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv);
static MaybeHandle<Object> MakeGenericError(
static Handle<JSObject> MakeGenericError(
Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
FrameSkipMode mode);

View File

@ -1267,9 +1267,10 @@ Handle<Context> Factory::NewScriptContext(Handle<NativeContext> outer,
Handle<ScopeInfo> scope_info) {
DCHECK_EQ(scope_info->scope_type(), SCRIPT_SCOPE);
int variadic_part_length = scope_info->ContextLength();
Handle<Context> context = NewContext(
isolate()->script_context_map(), Context::SizeFor(variadic_part_length),
variadic_part_length, AllocationType::kOld);
Handle<Context> context =
NewContext(handle(outer->script_context_map(), isolate()),
Context::SizeFor(variadic_part_length), variadic_part_length,
AllocationType::kOld);
context->set_scope_info(*scope_info);
context->set_previous(*outer);
DCHECK(context->IsScriptContext());
@ -2084,51 +2085,30 @@ Handle<FreshlyAllocatedBigInt> Factory::NewBigInt(int length,
return handle(bigint, isolate());
}
Handle<Object> Factory::NewError(Handle<JSFunction> constructor,
MessageTemplate template_index,
Handle<Object> arg0, Handle<Object> arg1,
Handle<Object> arg2) {
Handle<JSObject> Factory::NewError(Handle<JSFunction> constructor,
MessageTemplate template_index,
Handle<Object> arg0, Handle<Object> arg1,
Handle<Object> arg2) {
HandleScope scope(isolate());
if (isolate()->bootstrapper()->IsActive()) {
// During bootstrapping we cannot construct error objects.
return scope.CloseAndEscape(NewStringFromAsciiChecked(
MessageFormatter::TemplateString(template_index)));
}
if (arg0.is_null()) arg0 = undefined_value();
if (arg1.is_null()) arg1 = undefined_value();
if (arg2.is_null()) arg2 = undefined_value();
Handle<Object> result;
if (!ErrorUtils::MakeGenericError(isolate(), constructor, template_index,
arg0, arg1, arg2, SKIP_NONE)
.ToHandle(&result)) {
// If an exception is thrown while
// running the factory method, use the exception as the result.
DCHECK(isolate()->has_pending_exception());
result = handle(isolate()->pending_exception(), isolate());
isolate()->clear_pending_exception();
}
return scope.CloseAndEscape(result);
return scope.CloseAndEscape(ErrorUtils::MakeGenericError(
isolate(), constructor, template_index, arg0, arg1, arg2, SKIP_NONE));
}
Handle<Object> Factory::NewError(Handle<JSFunction> constructor,
Handle<String> message) {
Handle<JSObject> Factory::NewError(Handle<JSFunction> constructor,
Handle<String> message) {
// Construct a new error object. If an exception is thrown, use the exception
// as the result.
Handle<Object> no_caller;
MaybeHandle<Object> maybe_error = ErrorUtils::Construct(
isolate(), constructor, constructor, message, SKIP_NONE, no_caller,
ErrorUtils::StackTraceCollection::kDetailed);
if (maybe_error.is_null()) {
DCHECK(isolate()->has_pending_exception());
maybe_error = handle(isolate()->pending_exception(), isolate());
isolate()->clear_pending_exception();
}
return maybe_error.ToHandleChecked();
return ErrorUtils::Construct(isolate(), constructor, constructor, message,
SKIP_NONE, no_caller,
ErrorUtils::StackTraceCollection::kDetailed)
.ToHandleChecked();
}
Handle<Object> Factory::NewInvalidStringLengthError() {
@ -2143,9 +2123,9 @@ Handle<Object> Factory::NewInvalidStringLengthError() {
}
#define DEFINE_ERROR(NAME, name) \
Handle<Object> Factory::New##NAME(MessageTemplate template_index, \
Handle<Object> arg0, Handle<Object> arg1, \
Handle<Object> arg2) { \
Handle<JSObject> Factory::New##NAME( \
MessageTemplate template_index, Handle<Object> arg0, \
Handle<Object> arg1, Handle<Object> arg2) { \
return NewError(isolate()->name##_function(), template_index, arg0, arg1, \
arg2); \
}

View File

@ -770,24 +770,24 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<BytecodeArray> CopyBytecodeArray(Handle<BytecodeArray>);
// Interface for creating error objects.
Handle<Object> NewError(Handle<JSFunction> constructor,
Handle<String> message);
Handle<JSObject> NewError(Handle<JSFunction> constructor,
Handle<String> message);
Handle<Object> NewInvalidStringLengthError();
inline Handle<Object> NewURIError();
Handle<Object> NewError(Handle<JSFunction> constructor,
MessageTemplate template_index,
Handle<Object> arg0 = Handle<Object>(),
Handle<Object> arg1 = Handle<Object>(),
Handle<Object> arg2 = Handle<Object>());
Handle<JSObject> NewError(Handle<JSFunction> constructor,
MessageTemplate template_index,
Handle<Object> arg0 = Handle<Object>(),
Handle<Object> arg1 = Handle<Object>(),
Handle<Object> arg2 = Handle<Object>());
#define DECLARE_ERROR(NAME) \
Handle<Object> New##NAME(MessageTemplate template_index, \
Handle<Object> arg0 = Handle<Object>(), \
Handle<Object> arg1 = Handle<Object>(), \
Handle<Object> arg2 = Handle<Object>());
#define DECLARE_ERROR(NAME) \
Handle<JSObject> New##NAME(MessageTemplate template_index, \
Handle<Object> arg0 = Handle<Object>(), \
Handle<Object> arg1 = Handle<Object>(), \
Handle<Object> arg2 = Handle<Object>());
DECLARE_ERROR(Error)
DECLARE_ERROR(EvalError)
DECLARE_ERROR(RangeError)

View File

@ -1166,7 +1166,7 @@ void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
BuildGeneratorPrologue();
}
if (closure_scope()->NeedsContext()) {
if (closure_scope()->NeedsContext() && !closure_scope()->is_script_scope()) {
// Push a new inner context scope for the function.
BuildNewLocalActivationContext();
ContextScope local_function_context(this, closure_scope());
@ -1320,8 +1320,7 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
switch (variable->location()) {
case VariableLocation::UNALLOCATED:
globals_builder()->record_global_declaration();
break;
UNREACHABLE();
case VariableLocation::LOCAL:
if (variable->binding_needs_init()) {
Register destination(builder()->Local(variable->index()));
@ -1376,9 +1375,7 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
switch (variable->location()) {
case VariableLocation::UNALLOCATED:
AddToEagerLiteralsIfEager(decl->fun());
globals_builder()->record_global_declaration();
break;
UNREACHABLE();
case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: {
VisitFunctionLiteral(decl->fun());
@ -1435,9 +1432,26 @@ void BytecodeGenerator::VisitModuleNamespaceImports() {
void BytecodeGenerator::VisitGlobalDeclarations(Declaration::List* decls) {
RegisterAllocationScope register_scope(this);
VisitDeclarations(decls);
bool has_global_declaration = false;
for (Declaration* decl : *decls) {
Variable* var = decl->var();
DCHECK(var->is_used());
if (var->location() == VariableLocation::UNALLOCATED) {
// var or function.
has_global_declaration = true;
if (decl->IsFunctionDeclaration()) {
FunctionDeclaration* f = static_cast<FunctionDeclaration*>(decl);
AddToEagerLiteralsIfEager(f->fun());
}
} else {
// let or const. Handled in NewScriptContext.
DCHECK(decl->IsVariableDeclaration());
DCHECK(IsLexicalVariableMode(var->mode()));
}
}
if (!globals_builder()->has_global_declaration()) return;
if (!has_global_declaration) return;
globals_builder()->record_global_declaration();
DCHECK(!globals_builder()->processed());
globals_builder()->set_constant_pool_entry(
@ -5982,13 +5996,7 @@ void BytecodeGenerator::BuildNewLocalActivationContext() {
DCHECK_EQ(current_scope(), closure_scope());
// Create the appropriate context.
if (scope->is_script_scope()) {
Register scope_reg = register_allocator()->NewRegister();
builder()
->LoadLiteral(scope)
.StoreAccumulatorInRegister(scope_reg)
.CallRuntime(Runtime::kNewScriptContext, scope_reg);
} else if (scope->is_module_scope()) {
if (scope->is_module_scope()) {
// We don't need to do anything for the outer script scope.
DCHECK(scope->outer_scope()->is_script_scope());

View File

@ -581,6 +581,10 @@ ScopeType ScopeInfo::scope_type() const {
return ScopeTypeBits::decode(Flags());
}
bool ScopeInfo::is_script_scope() const {
return length() > 0 && scope_type() == SCRIPT_SCOPE;
}
bool ScopeInfo::SloppyEvalCanExtendVars() const {
bool sloppy_eval_can_extend_vars =
length() > 0 && SloppyEvalCanExtendVarsBit::decode(Flags());

View File

@ -196,6 +196,8 @@ class ScopeInfo : public FixedArray, public TorqueGeneratedScopeFlagsFields {
// Return the outer ScopeInfo if present.
ScopeInfo OuterScopeInfo() const;
bool is_script_scope() const;
// Returns true if this ScopeInfo has a black list attached containing
// stack allocated local variables.
V8_EXPORT_PRIVATE bool HasLocalsBlackList() const;

View File

@ -148,6 +148,16 @@ void SharedFunctionInfo::SetName(String name) {
UpdateFunctionMapIndex();
}
bool SharedFunctionInfo::is_script() const {
return scope_info().is_script_scope() &&
Script::cast(script()).compilation_type() ==
Script::COMPILATION_TYPE_HOST;
}
bool SharedFunctionInfo::needs_script_context() const {
return is_script() && scope_info().ContextLocalCount() > 0;
}
AbstractCode SharedFunctionInfo::abstract_code() {
if (HasBytecodeArray()) {
return AbstractCode::cast(GetBytecodeArray());

View File

@ -223,6 +223,9 @@ class SharedFunctionInfo : public HeapObject,
inline void set_raw_scope_info(ScopeInfo scope_info,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline bool is_script() const;
inline bool needs_script_context() const;
// End position of this function in the script source.
V8_EXPORT_PRIVATE int EndPosition() const;

View File

@ -97,37 +97,9 @@ void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate,
isolate->debug()->OnCompileError(script);
Factory* factory = isolate->factory();
Handle<Object> error =
Handle<JSObject> error =
factory->NewSyntaxError(error_details_.message(), argument);
if (!error->IsJSObject()) {
isolate->Throw(*error, &location);
return;
}
Handle<JSObject> jserror = Handle<JSObject>::cast(error);
Handle<Name> key_start_pos = factory->error_start_pos_symbol();
Object::SetProperty(isolate, jserror, key_start_pos,
handle(Smi::FromInt(location.start_pos()), isolate),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Handle<Name> key_end_pos = factory->error_end_pos_symbol();
Object::SetProperty(isolate, jserror, key_end_pos,
handle(Smi::FromInt(location.end_pos()), isolate),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Handle<Name> key_script = factory->error_script_symbol();
Object::SetProperty(isolate, jserror, key_script, script,
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
isolate->Throw(*error, &location);
isolate->ThrowAt(error, &location);
}
Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(

View File

@ -597,76 +597,6 @@ RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
return *function;
}
static Object FindNameClash(Isolate* isolate, Handle<ScopeInfo> scope_info,
Handle<JSGlobalObject> global_object,
Handle<ScriptContextTable> script_context) {
for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
Handle<String> name(scope_info->ContextLocalName(var), isolate);
VariableMode mode = scope_info->ContextLocalMode(var);
ScriptContextTable::LookupResult lookup;
if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
Handle<Context> context = ScriptContextTable::GetContext(
isolate, script_context, lookup.context_index);
// If we are trying to re-declare a REPL-mode let as a let, allow it.
if (!(mode == VariableMode::kLet && lookup.mode == VariableMode::kLet &&
scope_info->IsReplModeScope() &&
context->scope_info().IsReplModeScope())) {
// ES#sec-globaldeclarationinstantiation 5.b:
// If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
// exception.
return ThrowRedeclarationError(isolate, name,
RedeclarationType::kSyntaxError);
}
}
}
if (IsLexicalVariableMode(mode)) {
LookupIterator it(isolate, global_object, name, global_object,
LookupIterator::OWN_SKIP_INTERCEPTOR);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
if ((maybe.FromJust() & DONT_DELETE) != 0) {
// ES#sec-globaldeclarationinstantiation 5.a:
// If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
// exception.
// ES#sec-globaldeclarationinstantiation 5.d:
// If hasRestrictedGlobal is true, throw a SyntaxError exception.
return ThrowRedeclarationError(isolate, name,
RedeclarationType::kSyntaxError);
}
JSGlobalObject::InvalidatePropertyCell(global_object, name);
}
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_NewScriptContext) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
Handle<NativeContext> native_context(NativeContext::cast(isolate->context()),
isolate);
Handle<JSGlobalObject> global_object(native_context->global_object(),
isolate);
Handle<ScriptContextTable> script_context_table(
native_context->script_context_table(), isolate);
Object name_clash_result =
FindNameClash(isolate, scope_info, global_object, script_context_table);
if (isolate->has_pending_exception()) return name_clash_result;
Handle<Context> result =
isolate->factory()->NewScriptContext(native_context, scope_info);
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context_table, result);
native_context->set_script_context_table(*new_script_context_table);
return *result;
}
RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());

View File

@ -396,7 +396,6 @@ namespace internal {
F(NewClosure_Tenured, 2, 1) \
F(NewFunctionContext, 1, 1) \
F(NewRestParameter, 1, 1) \
F(NewScriptContext, 1, 1) \
F(NewSloppyArguments, 3, 1) \
F(NewSloppyArguments_Generic, 1, 1) \
F(NewStrictArguments, 1, 1) \

View File

@ -15,7 +15,7 @@ Evaluating 'let a = 239;'
columnNumber : 0
exception : {
className : SyntaxError
description : SyntaxError: Identifier 'a' has already been declared at <anonymous>:1:1
description : SyntaxError: Identifier 'a' has already been declared
objectId : <objectId>
subtype : error
type : object
@ -27,7 +27,7 @@ Evaluating 'let a = 239;'
}
result : {
className : SyntaxError
description : SyntaxError: Identifier 'a' has already been declared at <anonymous>:1:1
description : SyntaxError: Identifier 'a' has already been declared
objectId : <objectId>
subtype : error
type : object