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 ab25374f73d4f6446d126cc23497f0e4e4392e5e..999cf4c59a71ccce5c896a30abe8011be3bbb329 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 1f37ad6aa7db4b1491dcd7599e09a79a30d73c90..3bbc9aa60ddbee8bcb77254f719597ebcda08fa3 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 9ca5b0b0afd280b8c7af5a29c814ca6b70bf4154..94b4cfc1f5a449621885f55e47694c56c8835c6f 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 5673db3a092a8765ace99214c7dfdc4ae3608f6c..eaa119ce61ed4c3ce9cc5207c24c3c647f3bf549 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 794a5ca7e75fefdab0c176b8a3839cf5098762b2..d78341e7c387f39b61fb3c33a499d64f128f02df 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 afd67fd53c5c0b30630734652d0027b5eadb233c..f65de4f4c8e0fdaba66c9f1aee55f8b19551185a 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 6c80fa841752cd03a1ca026ade76f933e638263e..b5e83dba6e3987d88c2138cf181944826148756c 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));