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:
parent
6f3cf7aaae
commit
36190b91d4
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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); \
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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());
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user