Commit 7ca72292 authored by neis's avatar neis Committed by Commit bot

[parsing] Be less pessimistic about maybe_assigned of parameters.

Instead of unconditionally setting maybe_assigned for parameters, treat
parameters like other variables except that at the end we set maybe_assigned if
the function has a sloppy arguments object.

R=adamk@chromium.org, mstarzinger@chromium.org
BUG=v8:5636

Review-Url: https://codereview.chromium.org/2578103002
Cr-Commit-Position: refs/heads/master@{#41731}
parent b4aadaec
......@@ -1946,6 +1946,7 @@ void DeclarationScope::AllocateParameterLocals() {
DCHECK_EQ(this, var->scope());
if (uses_sloppy_arguments) {
var->set_is_used();
var->set_maybe_assigned();
var->ForceContextAllocation();
}
AllocateParameter(var, i);
......
......@@ -1066,20 +1066,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
auto mode = is_simple || parameter->is_rest ? VAR : TEMPORARY;
if (!is_simple) scope->SetHasNonSimpleParameters();
bool is_optional = parameter->initializer != nullptr;
Variable* var =
scope->DeclareParameter(name, mode, is_optional, parameter->is_rest,
&is_duplicate, ast_value_factory());
scope->DeclareParameter(name, mode, is_optional, parameter->is_rest,
&is_duplicate, ast_value_factory());
if (is_duplicate &&
classifier()->is_valid_formal_parameter_list_without_duplicates()) {
classifier()->RecordDuplicateFormalParameterError(
scanner()->location());
}
if (is_sloppy(scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters
// that are assigned via the arguments array.
var->set_maybe_assigned();
}
}
}
......
......@@ -3432,6 +3432,95 @@ TEST(InnerAssignment) {
}
}
TEST(MaybeAssignedParameters) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
LocalContext env;
struct {
bool arg_assigned;
const char* source;
} tests[] = {
{false, "function f(arg) {}"},
{false, "function f(arg) {g(arg)}"},
{false, "function f(arg) {function h() { g(arg) }; h()}"},
{false, "function f(arg) {function h() { g(arg) }; return h}"},
{false, "function f(arg=1) {}"},
{false, "function f(arg=1) {g(arg)}"},
{false, "function f(arg, arguments) {g(arg); arguments[0] = 42; g(arg)}"},
{false,
"function f(arg, ...arguments) {g(arg); arguments[0] = 42; g(arg)}"},
{false,
"function f(arg, arguments=[]) {g(arg); arguments[0] = 42; g(arg)}"},
{false, "function f(...arg) {g(arg); arguments[0] = 42; g(arg)}"},
// strict arguments object
{false, "function f(arg, x=1) {g(arg); arguments[0] = 42; g(arg)}"},
{false, "function f(arg, ...x) {g(arg); arguments[0] = 42; g(arg)}"},
{false, "function f(arg=1) {g(arg); arguments[0] = 42; g(arg)}"},
{false,
"function f(arg) {'use strict'; g(arg); arguments[0] = 42; g(arg)}"},
{false, "function f(arg) {g(arg); f.arguments[0] = 42; g(arg)}"},
{false, "function f(arg, args=arguments) {g(arg); args[0] = 42; g(arg)}"},
{true, "function f(arg) {g(arg); arg = 42; g(arg)}"},
{true, "function f(arg) {g(arg); eval('arg = 42'); g(arg)}"},
{true, "function f(arg) {g(arg); var arg = 42; g(arg)}"},
{true, "function f(arg, x=1) {g(arg); arg = 42; g(arg)}"},
{true, "function f(arg, ...x) {g(arg); arg = 42; g(arg)}"},
{true, "function f(arg=1) {g(arg); arg = 42; g(arg)}"},
{true, "function f(arg) {'use strict'; g(arg); arg = 42; g(arg)}"},
{true, "function f(arg, {a=(g(arg), arg=42)}) {g(arg)}"},
{true, "function f(arg) {g(arg); g(() => arg = 42); g(arg)}"},
{true, "function f(arg) {g(arg); g(() => eval('arg = 42')); g(arg)}"},
{true, "function f(arg) {g(arg); g(() => arguments[0] = 42); g(arg)}"},
{true, "function f(...arg) {g(arg); eval('arg = 42'); g(arg)}"},
// sloppy arguments object
{true, "function f(arg) {g(arg); arguments[0] = 42; g(arg)}"},
{true, "function f(arg) {g(arg); h(arguments); g(arg)}"},
{true,
"function f(arg) {((args) => {arguments[0] = 42})(arguments); "
"g(arg)}"},
{true, "function f(arg) {g(arg); eval('arguments[0] = 42'); g(arg)}"},
};
const char* suffix = "; f";
for (unsigned i = 0; i < arraysize(tests); ++i) {
bool assigned = tests[i].arg_assigned;
const char* source = tests[i].source;
for (unsigned allow_lazy = 0; allow_lazy < 2; ++allow_lazy) {
i::ScopedVector<char> program(Utf8LengthHelper(source) +
Utf8LengthHelper(suffix) + 1);
i::SNPrintF(program, "%s%s", source, suffix);
i::Zone zone(isolate->allocator(), ZONE_NAME);
std::unique_ptr<i::ParseInfo> info;
printf("%s\n", program.start());
v8::Local<v8::Value> v = CompileRun(program.start());
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
i::Handle<i::SharedFunctionInfo> shared = i::handle(f->shared());
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(&zone, shared));
info->set_allow_lazy_parsing(allow_lazy);
CHECK(i::parsing::ParseFunction(info.get()));
CHECK(i::Compiler::Analyze(info.get()));
CHECK_NOT_NULL(info->literal());
i::Scope* scope = info->literal()->scope();
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
CHECK_NULL(scope->sibling());
CHECK(scope->is_function_scope());
const i::AstRawString* var_name =
info->ast_value_factory()->GetOneByteString("arg");
i::Variable* var = scope->Lookup(var_name);
CHECK(var->is_used() || !assigned);
bool is_maybe_assigned = var->maybe_assigned() == i::kMaybeAssigned;
CHECK_EQ(is_maybe_assigned, assigned);
}
}
}
namespace {
i::Scope* DeserializeFunctionScope(i::Isolate* isolate, i::Zone* zone,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment