Commit 1dbd6369 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Correctly compute line numbers in functions from the function constructor.

R=aandrey@chromium.org
BUG=chromium:109362
LOG=Y

Review URL: https://codereview.chromium.org/701093003

Cr-Commit-Position: refs/heads/master@{#25289}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25289 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ad815be7
......@@ -272,8 +272,8 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
int position = static_cast<int>(it.rinfo()->data());
if (position >= 0) {
int pc_offset = static_cast<int>(it.rinfo()->pc() - code->address());
int line_number = script->GetLineNumber(position) + 1;
line_table->SetPosition(pc_offset, line_number);
int line_number = script->GetLineNumber(position);
line_table->SetPosition(pc_offset, line_number + 1);
}
}
}
......
......@@ -44,13 +44,7 @@ function GeneratorFunctionPrototypeConstructor(x) {
}
function GeneratorFunctionConstructor(arg1) { // length == 1
var source = NewFunctionString(arguments, 'function*');
var global_proxy = %GlobalProxy(global);
// Compile the string in the constructor and not a helper so that errors
// appear to come from here.
var f = %_CallFunction(global_proxy, %CompileString(source, true));
%FunctionMarkNameShouldPrintAsAnonymous(f);
return f;
return NewFunctionFromString(arguments, 'function*');
}
......
......@@ -392,34 +392,26 @@ function MakeReferenceErrorEmbedded(type, arg) {
else the line number.
*/
function ScriptLineFromPosition(position) {
var lower = 0;
var upper = this.lineCount() - 1;
var line_ends = this.line_ends;
var upper = line_ends.length - 1;
if (upper < 0) return -1;
// We'll never find invalid positions so bail right away.
if (position > line_ends[upper]) {
return -1;
}
// This means we don't have to safe-guard indexing line_ends[i - 1].
if (position <= line_ends[0]) {
return 0;
}
// Binary search to find line # from position range.
while (upper >= 1) {
var i = (lower + upper) >> 1;
if (position > line_ends[i]) {
lower = i + 1;
} else if (position <= line_ends[i - 1]) {
upper = i - 1;
if (position > line_ends[upper]) return -1;
if (position <= line_ends[0]) return 0;
var lower = 1;
// Binary search.
while (true) {
var mid = (upper + lower) >> 1;
if (position <= line_ends[mid - 1]) {
upper = mid - 1;
} else if (position > line_ends[mid]){
lower = mid + 1;
} else {
return i;
return mid;
}
}
return -1;
}
/**
......
......@@ -9932,27 +9932,31 @@ int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
}
int Script::GetLineNumberWithArray(int code_pos) {
int Script::GetLineNumberWithArray(int position) {
DisallowHeapAllocation no_allocation;
DCHECK(line_ends()->IsFixedArray());
FixedArray* line_ends_array = FixedArray::cast(line_ends());
int line_ends_len = line_ends_array->length();
if (line_ends_len == 0) return -1;
FixedArray* line_ends = FixedArray::cast(this->line_ends());
int upper = line_ends->length() - 1;
if (upper < 0) return -1;
int offset = line_offset()->value();
if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
return line_offset()->value();
if (position > Smi::cast(line_ends->get(upper))->value()) {
return upper + 1 + offset;
}
if (position <= Smi::cast(line_ends->get(0))->value()) return offset;
int left = 0;
int right = line_ends_len;
while (int half = (right - left) / 2) {
if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
right -= half;
int lower = 1;
// Binary search.
while (true) {
int mid = (lower + upper) / 2;
if (position <= Smi::cast(line_ends->get(mid - 1))->value()) {
upper = mid - 1;
} else if (position > Smi::cast(line_ends->get(mid))->value()) {
lower = mid + 1;
} else {
left += half;
return mid + offset;
}
}
return right + line_offset()->value();
return -1;
}
......
......@@ -347,9 +347,10 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate,
RUNTIME_FUNCTION(Runtime_CompileString) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
CONVERT_SMI_ARG_CHECKED(source_offset, 2);
// Extract native context.
Handle<Context> context(isolate->native_context());
......@@ -375,6 +376,14 @@ RUNTIME_FUNCTION(Runtime_CompileString) {
isolate, fun,
Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
restriction, RelocInfo::kNoPosition));
if (function_literal_only) {
// The actual body is wrapped, which shifts line numbers.
Handle<Script> script(Script::cast(fun->shared()->script()), isolate);
if (script->line_offset() == 0) {
int line_num = Script::GetLineNumber(script, source_offset);
script->set_line_offset(Smi::FromInt(-line_num));
}
}
return *fun;
}
......
......@@ -251,7 +251,7 @@ namespace internal {
F(DateCacheVersion, 0, 1) \
\
/* Globals */ \
F(CompileString, 2, 1) \
F(CompileString, 3, 1) \
\
/* Eval */ \
F(GlobalProxy, 1, 1) \
......
......@@ -175,7 +175,7 @@ function GlobalEval(x) {
var global_proxy = %GlobalProxy(global);
var f = %CompileString(x, false);
var f = %CompileString(x, false, 0);
if (!IS_FUNCTION(f)) return f;
return %_CallFunction(global_proxy, f);
......@@ -1829,7 +1829,7 @@ function FunctionBind(this_arg) { // Length is 1.
}
function NewFunctionString(arguments, function_token) {
function NewFunctionFromString(arguments, function_token) {
var n = arguments.length;
var p = '';
if (n > 1) {
......@@ -1846,21 +1846,20 @@ function NewFunctionString(arguments, function_token) {
// If the formal parameters include an unbalanced block comment, the
// function must be rejected. Since JavaScript does not allow nested
// comments we can include a trailing block comment to catch this.
p += '\n/' + '**/';
p += '\n\x2f**\x2f';
}
var body = (n > 0) ? ToString(arguments[n - 1]) : '';
return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
var head = '(' + function_token + '(' + p + ') {\n';
var src = head + body + '\n})';
var global_proxy = %GlobalProxy(global);
var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
%FunctionMarkNameShouldPrintAsAnonymous(f);
return f;
}
function FunctionConstructor(arg1) { // length == 1
var source = NewFunctionString(arguments, 'function');
var global_proxy = %GlobalProxy(global);
// Compile the string in the constructor and not a helper so that errors
// appear to come from here.
var f = %_CallFunction(global_proxy, %CompileString(source, true));
%FunctionMarkNameShouldPrintAsAnonymous(f);
return f;
return NewFunctionFromString(arguments, 'function');
}
......
......@@ -27,6 +27,6 @@
// Flags: --allow-natives-syntax
var single_function_good = "(function() { return 5; })";
%CompileString(single_function_good, true);
%CompileString(single_function_good, true, 0);
var single_function_bad = "(function() { return 5; })();";
%CompileString(single_function_bad, true);
%CompileString(single_function_bad, true, 0);
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function test(expectation, f) {
var stack;
try {
f();
} catch (e) {
stack = e.stack;
}
print(stack);
assertTrue(stack.indexOf("at eval (evaltest:" + expectation + ")") > 0);
}
test("1:5", new Function(
'1 + reference_error //@ sourceURL=evaltest'));
test("2:6", new Function(
'x', '\n 1 + reference_error //@ sourceURL=evaltest'));
test("2:6", new Function(
'x\n\n', "z//\n", "y", '\n 1 + reference_error //@ sourceURL=evaltest'));
test("1:5", new Function(
'x/*', "z//\n", "y*/", '1 + reference_error //@ sourceURL=evaltest'));
test("2:6", eval(
'(function () {\n 1 + reference_error //@ sourceURL=evaltest\n})'));
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