Make sure that the body of the function created by calling Function is
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 25 Sep 2008 07:35:45 +0000 (07:35 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 25 Sep 2008 07:35:45 +0000 (07:35 +0000)
on a line of its own.  This allows the body to be terminated by a
single-line comment.

Also, make sure to set the name of the function to anonymous after the
fact so that recursion through the name anonymous is not allowed and
so that global variables called anonymous are not shadowed.

This is a fix for http://code.google.com/p/v8/issues/detail?id=85
Review URL: http://codereview.chromium.org/4248

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@370 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler.cc
src/compiler.h
src/debug-delay.js
src/runtime.cc
src/runtime.h
src/v8natives.js
test/mjsunit/function.js

index ab25374..999cf4c 100644 (file)
@@ -202,8 +202,9 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
 }
 
 
-Handle<JSFunction> Compiler::CompileEval(bool is_global,
-                                         Handle<String> source) {
+Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
+                                         int line_offset,
+                                         bool is_global) {
   Counters::total_eval_size.Increment(source->length());
   Counters::total_compile_size.Increment(source->length());
 
@@ -219,6 +220,7 @@ Handle<JSFunction> Compiler::CompileEval(bool is_global,
   if (result.is_null()) {
     // Create a script object describing the script to be compiled.
     Handle<Script> script = Factory::NewScript(source);
+    script->set_line_offset(Smi::FromInt(line_offset));
     result = MakeFunction(is_global, true, script, NULL, NULL);
     if (!result.is_null()) {
       CompilationCache::Associate(source, entry, result);
index 1f37ad6..3bbc9aa 100644 (file)
@@ -57,7 +57,9 @@ class Compiler : public AllStatic {
                                     ScriptDataImpl* script_Data);
 
   // Compile a String source within a context for Eval.
-  static Handle<JSFunction> CompileEval(bool is_global, Handle<String> source);
+  static Handle<JSFunction> CompileEval(Handle<String> source,
+                                        int line_offset,
+                                        bool is_global);
 
   // Compile from function info (used for lazy compilation). Returns
   // true on success and false if the compilation resulted in a stack
index 9ca5b0b..94b4cfc 100644 (file)
@@ -1230,7 +1230,7 @@ DebugCommandProcessor.prototype.scriptsCommandToJSONRequest_ = function(args) {
 DebugCommandProcessor.prototype.responseToText = function(json_response) {
   try {
     // Convert the JSON string to an object.
-    response = %CompileString('(' + json_response + ')', false)();
+    response = %CompileString('(' + json_response + ')', 0, false)();
 
     if (!response.success) {
       return response.message;
@@ -1436,7 +1436,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request,
   try {
     try {
       // Convert the JSON string to an object.
-      request = %CompileString('(' + json_request + ')', false)();
+      request = %CompileString('(' + json_request + ')', 0, false)();
 
       // Create an initial response.
       response = this.createResponse(request);
@@ -1889,7 +1889,7 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
 DebugCommandProcessor.prototype.isRunning = function(json_response) {
   try {
     // Convert the JSON string to an object.
-    response = %CompileString('(' + json_response + ')', false)();
+    response = %CompileString('(' + json_response + ')', 0, false)();
 
     // Return whether VM should be running after this request.
     return response.running;
index 5673db3..eaa119c 100644 (file)
@@ -726,6 +726,17 @@ static Object* Runtime_FunctionGetName(Arguments args) {
 }
 
 
+static Object* Runtime_FunctionSetName(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, f, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  f->shared()->set_name(name);
+  return Heap::undefined_value();
+}
+
+
 static Object* Runtime_FunctionGetScript(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 1);
@@ -3361,10 +3372,11 @@ static Object* Runtime_EvalReceiver(Arguments args) {
 
 static Object* Runtime_CompileString(Arguments args) {
   HandleScope scope;
-  ASSERT(args.length() == 2);
+  ASSERT(args.length() == 3);
   CONVERT_ARG_CHECKED(String, source, 0);
-  bool contextual = args[1]->IsTrue();
-  RUNTIME_ASSERT(contextual || args[1]->IsFalse());
+  CONVERT_ARG_CHECKED(Smi, line_offset, 1);
+  bool contextual = args[2]->IsTrue();
+  RUNTIME_ASSERT(contextual || args[2]->IsFalse());
 
   // Compute the eval context.
   Handle<Context> context;
@@ -3383,7 +3395,7 @@ static Object* Runtime_CompileString(Arguments args) {
   // Compile source string.
   bool is_global = context->IsGlobalContext();
   Handle<JSFunction> boilerplate =
-      Compiler::CompileEval(is_global, source);
+      Compiler::CompileEval(source, line_offset->value(), is_global);
   if (boilerplate.is_null()) return Failure::Exception();
   Handle<JSFunction> fun =
       Factory::NewFunctionFromBoilerplate(boilerplate, context);
@@ -4502,7 +4514,7 @@ static Object* Runtime_DebugEvaluate(Arguments args) {
       Factory::NewStringFromAscii(Vector<const char>(source_str,
                                                      source_str_length));
   Handle<JSFunction> boilerplate =
-      Compiler::CompileEval(context->IsGlobalContext(), function_source);
+      Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
   if (boilerplate.is_null()) return Failure::Exception();
   Handle<JSFunction> compiled_function =
       Factory::NewFunctionFromBoilerplate(boilerplate, context);
@@ -4558,7 +4570,7 @@ static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
   Handle<Context> context = Top::global_context();
 
   // Compile the source to be evaluated.
-  Handle<JSFunction> boilerplate(Compiler::CompileEval(true, source));
+  Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
   if (boilerplate.is_null()) return Failure::Exception();
   Handle<JSFunction> compiled_function =
       Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
index 794a5ca..d78341e 100644 (file)
@@ -157,6 +157,7 @@ namespace v8 { namespace internal {
   F(FunctionSetLength, 2) \
   F(FunctionSetPrototype, 2) \
   F(FunctionGetName, 1) \
+  F(FunctionSetName, 2) \
   F(FunctionGetSourceCode, 1) \
   F(FunctionGetScript, 1) \
   F(FunctionGetScriptSourcePosition, 1) \
@@ -180,7 +181,7 @@ namespace v8 { namespace internal {
   F(NumberIsFinite, 1) \
   \
   /* Globals */ \
-  F(CompileString, 2) \
+  F(CompileString, 3) \
   F(CompileScript, 4) \
   F(GlobalPrint, 1) \
   \
index afd67fd..f65de4f 100644 (file)
@@ -201,7 +201,7 @@ $Object.prototype.constructor = $Object;
 %AddProperty(global, "eval", function(x) {
   if (!IS_STRING(x)) return x;
 
-  var f = %CompileString(x, true);
+  var f = %CompileString(x, 0, true);
   if (!IS_FUNCTION(f)) return f;
 
   return f.call(%EvalReceiver(this));
@@ -212,7 +212,7 @@ $Object.prototype.constructor = $Object;
 %AddProperty(global, "execScript", function(expr, lang) {
   // NOTE: We don't care about the character casing.
   if (!lang || /javascript/i.test(lang)) {
-    var f = %CompileString(ToString(expr), false);
+    var f = %CompileString(ToString(expr), 0, false);
     f.call(global);
   }
   return null;
@@ -406,11 +406,13 @@ function NewFunction(arg1) {  // length == 1
     if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
   }
   var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
-  var source = '(function anonymous(' + p + ') { ' + body + ' })';
+  var source = '(function(' + p + ') {\n' + body + '\n})';
 
   // The call to SetNewFunctionAttributes will ensure the prototype
   // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
-  return %SetNewFunctionAttributes(%CompileString(source, false)());
+  var f = %CompileString(source, -1, false)();
+  %FunctionSetName(f, "anonymous");
+  return %SetNewFunctionAttributes(f);
 };
 
 %SetCode($Function, NewFunction);
index 6c80fa8..b5e83db 100644 (file)
 
 var f = Function();
 assertTrue(typeof f() == 'undefined');
-var f = new Function();
+f = new Function();
 assertTrue(typeof f() == 'undefined');
 
-var f = Function('return 1');
+f = Function('return 1');
 assertEquals(1, f());
-var f = new Function('return 1');
+f = new Function('return 1');
 assertEquals(1, f());
 
-var f = Function('return true');
+f = Function('return true');
 assertTrue(f());
-var f = new Function('return true');
+f = new Function('return true');
 assertTrue(f());
 
-var f = Function('x', 'return x')
+f = Function('x', 'return x');
 assertEquals(1, f(1));
 assertEquals('bar', f('bar'));
 assertTrue(typeof f() == 'undefined');
 var x = {};
 assertTrue(x === f(x));
-var f = new Function('x', 'return x')
+
+f = Function('x', 'return x // comment');
+assertEquals(1, f(1));
+
+f = Function('return typeof anonymous');
+assertEquals('undefined', f());
+
+var anonymous = 42;
+f = Function('return anonymous;');
+assertEquals(42, f());
+
+f = new Function('x', 'return x')
 assertEquals(1, f(1));
 assertEquals('bar', f('bar'));
 assertTrue(typeof f() == 'undefined');
 var x = {};
 assertTrue(x === f(x));
 
-var f = Function('x', 'y', 'return x+y');
+f = Function('x', 'y', 'return x+y');
 assertEquals(5, f(2, 3));
 assertEquals('foobar', f('foo', 'bar'));
-var f = new Function('x', 'y', 'return x+y');
+f = new Function('x', 'y', 'return x+y');
 assertEquals(5, f(2, 3));
 assertEquals('foobar', f('foo', 'bar'));
 
@@ -66,7 +77,7 @@ var z = {}; z.toString = function() { return 'return x*y'; }
 var f = Function(x, y, z);
 assertEquals(25, f(5, 5));
 assertEquals(42, f(2, 21));
-var f = new Function(x, y, z);
+f = new Function(x, y, z);
 assertEquals(25, f(5, 5));
 assertEquals(42, f(2, 21));