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, ...@@ -272,8 +272,8 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
int position = static_cast<int>(it.rinfo()->data()); int position = static_cast<int>(it.rinfo()->data());
if (position >= 0) { if (position >= 0) {
int pc_offset = static_cast<int>(it.rinfo()->pc() - code->address()); int pc_offset = static_cast<int>(it.rinfo()->pc() - code->address());
int line_number = script->GetLineNumber(position) + 1; int line_number = script->GetLineNumber(position);
line_table->SetPosition(pc_offset, line_number); line_table->SetPosition(pc_offset, line_number + 1);
} }
} }
} }
......
...@@ -44,13 +44,7 @@ function GeneratorFunctionPrototypeConstructor(x) { ...@@ -44,13 +44,7 @@ function GeneratorFunctionPrototypeConstructor(x) {
} }
function GeneratorFunctionConstructor(arg1) { // length == 1 function GeneratorFunctionConstructor(arg1) { // length == 1
var source = NewFunctionString(arguments, 'function*'); return NewFunctionFromString(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;
} }
......
...@@ -392,34 +392,26 @@ function MakeReferenceErrorEmbedded(type, arg) { ...@@ -392,34 +392,26 @@ function MakeReferenceErrorEmbedded(type, arg) {
else the line number. else the line number.
*/ */
function ScriptLineFromPosition(position) { function ScriptLineFromPosition(position) {
var lower = 0;
var upper = this.lineCount() - 1;
var line_ends = this.line_ends; 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. // We'll never find invalid positions so bail right away.
if (position > line_ends[upper]) { if (position > line_ends[upper]) return -1;
return -1; if (position <= line_ends[0]) return 0;
}
var lower = 1;
// This means we don't have to safe-guard indexing line_ends[i - 1]. // Binary search.
if (position <= line_ends[0]) { while (true) {
return 0; var mid = (upper + lower) >> 1;
} if (position <= line_ends[mid - 1]) {
upper = mid - 1;
// Binary search to find line # from position range. } else if (position > line_ends[mid]){
while (upper >= 1) { lower = mid + 1;
var i = (lower + upper) >> 1;
if (position > line_ends[i]) {
lower = i + 1;
} else if (position <= line_ends[i - 1]) {
upper = i - 1;
} else { } else {
return i; return mid;
} }
} }
return -1;
} }
/** /**
......
...@@ -9932,27 +9932,31 @@ int Script::GetColumnNumber(Handle<Script> script, int code_pos) { ...@@ -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; DisallowHeapAllocation no_allocation;
DCHECK(line_ends()->IsFixedArray()); FixedArray* line_ends = FixedArray::cast(this->line_ends());
FixedArray* line_ends_array = FixedArray::cast(line_ends()); int upper = line_ends->length() - 1;
int line_ends_len = line_ends_array->length(); if (upper < 0) return -1;
if (line_ends_len == 0) return -1; int offset = line_offset()->value();
if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) { if (position > Smi::cast(line_ends->get(upper))->value()) {
return line_offset()->value(); return upper + 1 + offset;
} }
if (position <= Smi::cast(line_ends->get(0))->value()) return offset;
int left = 0; int lower = 1;
int right = line_ends_len; // Binary search.
while (int half = (right - left) / 2) { while (true) {
if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { int mid = (lower + upper) / 2;
right -= half; 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 { } else {
left += half; return mid + offset;
} }
} }
return right + line_offset()->value(); return -1;
} }
......
...@@ -347,9 +347,10 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate, ...@@ -347,9 +347,10 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate,
RUNTIME_FUNCTION(Runtime_CompileString) { RUNTIME_FUNCTION(Runtime_CompileString) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(String, source, 0); CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
CONVERT_SMI_ARG_CHECKED(source_offset, 2);
// Extract native context. // Extract native context.
Handle<Context> context(isolate->native_context()); Handle<Context> context(isolate->native_context());
...@@ -375,6 +376,14 @@ RUNTIME_FUNCTION(Runtime_CompileString) { ...@@ -375,6 +376,14 @@ RUNTIME_FUNCTION(Runtime_CompileString) {
isolate, fun, isolate, fun,
Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY, Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
restriction, RelocInfo::kNoPosition)); 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; return *fun;
} }
......
...@@ -251,7 +251,7 @@ namespace internal { ...@@ -251,7 +251,7 @@ namespace internal {
F(DateCacheVersion, 0, 1) \ F(DateCacheVersion, 0, 1) \
\ \
/* Globals */ \ /* Globals */ \
F(CompileString, 2, 1) \ F(CompileString, 3, 1) \
\ \
/* Eval */ \ /* Eval */ \
F(GlobalProxy, 1, 1) \ F(GlobalProxy, 1, 1) \
......
...@@ -175,7 +175,7 @@ function GlobalEval(x) { ...@@ -175,7 +175,7 @@ function GlobalEval(x) {
var global_proxy = %GlobalProxy(global); var global_proxy = %GlobalProxy(global);
var f = %CompileString(x, false); var f = %CompileString(x, false, 0);
if (!IS_FUNCTION(f)) return f; if (!IS_FUNCTION(f)) return f;
return %_CallFunction(global_proxy, f); return %_CallFunction(global_proxy, f);
...@@ -1829,7 +1829,7 @@ function FunctionBind(this_arg) { // Length is 1. ...@@ -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 n = arguments.length;
var p = ''; var p = '';
if (n > 1) { if (n > 1) {
...@@ -1846,21 +1846,20 @@ function NewFunctionString(arguments, function_token) { ...@@ -1846,21 +1846,20 @@ function NewFunctionString(arguments, function_token) {
// If the formal parameters include an unbalanced block comment, the // If the formal parameters include an unbalanced block comment, the
// function must be rejected. Since JavaScript does not allow nested // function must be rejected. Since JavaScript does not allow nested
// comments we can include a trailing block comment to catch this. // 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]) : ''; 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 function FunctionConstructor(arg1) { // length == 1
var source = NewFunctionString(arguments, 'function'); return NewFunctionFromString(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;
} }
......
...@@ -27,6 +27,6 @@ ...@@ -27,6 +27,6 @@
// Flags: --allow-natives-syntax // Flags: --allow-natives-syntax
var single_function_good = "(function() { return 5; })"; 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; })();"; 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