Add fuzzing support for inline runtime functions
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Mar 2010 09:27:12 +0000 (09:27 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Mar 2010 09:27:12 +0000 (09:27 +0000)
The inline runtime functions are now included in the fuzzing of the natives. The chack for the expected number of arguments passed have been moved to the parser which will generate a syntax error if a runtime function (either C++ or inline) is called with a different number of arguments than expected.
Review URL: http://codereview.chromium.org/573056

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

14 files changed:
src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/codegen.cc
src/codegen.h
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/math.js
src/messages.js
src/parser.cc
src/runtime.cc
src/x64/codegen-x64.cc
src/x64/codegen-x64.h
test/cctest/test-log-stack-tracer.cc
test/mjsunit/fuzz-natives.js

index 9e595825934c4fba66f8bfc3245674ebbecbda4c..eceba55e2a89a5bf0ae1f5bae5ba87667e58e6e6 100644 (file)
@@ -3597,7 +3597,7 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 1);
 
index bea98b669330989d15efed328e15a346b3b1ee2c..9ade70a048a424cca7098a268a6297e5ac9590ff 100644 (file)
@@ -197,6 +197,10 @@ class CodeGenerator: public AstVisitor {
 
   static const int kUnknownIntValue = -1;
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -326,6 +330,7 @@ class CodeGenerator: public AstVisitor {
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
 
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
@@ -360,7 +365,7 @@ class CodeGenerator: public AstVisitor {
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -396,14 +401,10 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
+  // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
-
-  // Fast call to sine function.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast support for Math.pow().
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
   // Simple condition analysis.
index 6841c21612b9b4066389dda653a36b7760c90a92..f9913b9c15bd5958614e028795f606b570739726 100644 (file)
@@ -351,42 +351,18 @@ void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
 }
 
 
+// List of special runtime calls which are generated inline. For some of these
+// functions the code will be generated inline, and for others a call to a code
+// stub will be inlined.
+
+#define INLINE_RUNTIME_ENTRY(Name, argc, ressize)                             \
+    {&CodeGenerator::Generate##Name,  "_" #Name, argc},                       \
 
-// Special cases: These 'runtime calls' manipulate the current
-// frame and are only used 1 or two places, so we generate them
-// inline instead of generating calls to them.  They are used
-// for implementing Function.prototype.call() and
-// Function.prototype.apply().
 CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
-  {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
-  {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
-  {&CodeGenerator::GenerateIsArray, "_IsArray"},
-  {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
-  {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
-  {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
-  {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
-  {&CodeGenerator::GenerateClassOf, "_ClassOf"},
-  {&CodeGenerator::GenerateValueOf, "_ValueOf"},
-  {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
-  {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
-  {&CodeGenerator::GenerateCharFromCode, "_CharFromCode"},
-  {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
-  {&CodeGenerator::GenerateLog, "_Log"},
-  {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
-  {&CodeGenerator::GenerateIsObject, "_IsObject"},
-  {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
-  {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
-  {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
-  {&CodeGenerator::GenerateSubString, "_SubString"},
-  {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
-  {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
-  {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
-  {&CodeGenerator::GenerateMathPow, "_Math_pow"},
-  {&CodeGenerator::GenerateMathSin, "_Math_sin"},
-  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
-  {&CodeGenerator::GenerateMathSqrt, "_Math_sqrt"},
+  INLINE_RUNTIME_FUNCTION_LIST(INLINE_RUNTIME_ENTRY)
 };
 
+#undef INLINE_RUNTIME_ENTRY
 
 CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
     Handle<String> name) {
@@ -431,6 +407,14 @@ bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
 }
 
 
+int CodeGenerator::InlineRuntimeCallArgumentsCount(Handle<String> name) {
+  CodeGenerator::InlineRuntimeLUT* f =
+      CodeGenerator::FindInlineRuntimeLUT(name);
+  if (f != NULL) return f->nargs;
+  return -1;
+}
+
+
 // Simple condition analysis.  ALWAYS_TRUE and ALWAYS_FALSE represent a
 // known result for the test expression, with no side effects.
 CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
index 8dcde84bbd74c25ee6c07aa7e6290d6c06a6de2f..40ed6cefe67467bca92c27b6fb30679964ece7f8 100644 (file)
@@ -99,6 +99,36 @@ namespace v8 {
 namespace internal {
 
 
+#define INLINE_RUNTIME_FUNCTION_LIST(F) \
+  F(IsSmi, 1, 1)                                                             \
+  F(IsNonNegativeSmi, 1, 1)                                                  \
+  F(IsArray, 1, 1)                                                           \
+  F(IsRegExp, 1, 1)                                                          \
+  F(IsConstructCall, 0, 1)                                                   \
+  F(ArgumentsLength, 0, 1)                                                   \
+  F(Arguments, 1, 1)                                                         \
+  F(ClassOf, 1, 1)                                                           \
+  F(ValueOf, 1, 1)                                                           \
+  F(SetValueOf, 2, 1)                                                        \
+  F(FastCharCodeAt, 2, 1)                                                    \
+  F(CharFromCode, 1, 1)                                                      \
+  F(ObjectEquals, 2, 1)                                                      \
+  F(Log, 3, 1)                                                               \
+  F(RandomPositiveSmi, 0, 1)                                                 \
+  F(IsObject, 1, 1)                                                          \
+  F(IsFunction, 1, 1)                                                        \
+  F(IsUndetectableObject, 1, 1)                                              \
+  F(StringAdd, 2, 1)                                                         \
+  F(SubString, 3, 1)                                                         \
+  F(StringCompare, 2, 1)                                                     \
+  F(RegExpExec, 4, 1)                                                        \
+  F(NumberToString, 1, 1)                                                    \
+  F(MathPow, 2, 1)                                                           \
+  F(MathSin, 1, 1)                                                           \
+  F(MathCos, 1, 1)                                                           \
+  F(MathSqrt, 1, 1)
+
+
 // Support for "structured" code comments.
 #ifdef DEBUG
 
index bdd1c4a3f447b0f9d1366820ebdb033aed17c8d1..a154d681c113484d24c047f69cebe36648962cbe 100644 (file)
@@ -5912,7 +5912,7 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
 
   // ArgumentsAccessStub expects the key in edx and the formal
index 79cad7268532219c8c97874a985f8bc9e73b0fc7..b0adebe840eac535ac5d9d9ccee2c2785b26983d 100644 (file)
@@ -339,6 +339,10 @@ class CodeGenerator: public AstVisitor {
   bool in_spilled_code() const { return in_spilled_code_; }
   void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -522,6 +526,7 @@ class CodeGenerator: public AstVisitor {
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
 
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
@@ -555,7 +560,7 @@ class CodeGenerator: public AstVisitor {
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -593,14 +598,10 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
+  // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
-
-  // Fast call to transcendental functions.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast case for sqrt
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
   // Simple condition analysis.
index f6cd055657e360a8600bc179608e59146912a214..2f74b8a06fe8859592ada6febff718869dc33f25 100644 (file)
@@ -1,4 +1,3 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -85,7 +84,7 @@ function MathCeil(x) {
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_cos(x);
+  return %_MathCos(x);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -160,7 +159,7 @@ function MathMin(arg1, arg2) {  // length == 2
 function MathPow(x, y) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
   if (!IS_NUMBER(y)) y = ToNumber(y);
-  return %_Math_pow(x, y);
+  return %_MathPow(x, y);
 }
 
 // ECMA 262 - 15.8.2.14
@@ -177,13 +176,13 @@ function MathRound(x) {
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_sin(x);
+  return %_MathSin(x);
 }
 
 // ECMA 262 - 15.8.2.17
 function MathSqrt(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %_Math_sqrt(x);
+  return %_MathSqrt(x);
 }
 
 // ECMA 262 - 15.8.2.18
index 5848115059b3ec5d91a6e567dff50503632bc2c4..cb392ff90f74c65db5cf151ae63df35e14bddd85 100644 (file)
@@ -182,7 +182,8 @@ function FormatMessage(message) {
       invalid_json:                 "String '%0' is not valid JSON",
       circular_structure:           "Converting circular structure to JSON",
       obj_ctor_property_non_object: "Object.%0 called on non-object",
-      array_indexof_not_defined:    "Array.getIndexOf: Argument undefined"
+      array_indexof_not_defined:    "Array.getIndexOf: Argument undefined",
+      illegal_access:               "illegal access"
     };
   }
   var format = kMessages[message.type];
index dd7266907d039d25401af301fc7a88e2fc1fc610..57cb0b5666ce8eab33eccf8f49c69015db98fef7 100644 (file)
@@ -30,6 +30,7 @@
 #include "api.h"
 #include "ast.h"
 #include "bootstrapper.h"
+#include "codegen.h"
 #include "compiler.h"
 #include "messages.h"
 #include "platform.h"
@@ -3832,7 +3833,27 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
     }
   }
 
-  // Otherwise we have a runtime call.
+  // Check that the expected number arguments are passed to runtime functions.
+  if (!is_pre_parsing_) {
+    if (function != NULL
+        && function->nargs != -1
+        && function->nargs != args->length()) {
+      ReportMessage("illegal_access", Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    } else if (function == NULL && !name.is_null()) {
+      // If this is not a runtime function implemented in C++ it might be an
+      // inlined runtime function.
+      int argc = CodeGenerator::InlineRuntimeCallArgumentsCount(name);
+      if (argc != -1 && argc != args->length()) {
+        ReportMessage("illegal_access", Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
+    }
+  }
+
+  // Otherwise we have a valid runtime call.
   return NEW(CallRuntime(name, function, args));
 }
 
index 20049df5f28012352813368d23ea31e541c4b226..c88bb85c95a0e686fa04664700b38c53b5ed01f2 100644 (file)
@@ -32,6 +32,7 @@
 #include "accessors.h"
 #include "api.h"
 #include "arguments.h"
+#include "codegen.h"
 #include "compiler.h"
 #include "cpu.h"
 #include "dateparser-inl.h"
@@ -8665,18 +8666,28 @@ static Object* Runtime_ListNatives(Arguments args) {
   HandleScope scope;
   Handle<JSArray> result = Factory::NewJSArray(0);
   int index = 0;
+  bool inline_runtime_functions = false;
 #define ADD_ENTRY(Name, argc, ressize)                                       \
   {                                                                          \
     HandleScope inner;                                                       \
-    Handle<String> name =                                                    \
-      Factory::NewStringFromAscii(                                           \
-          Vector<const char>(#Name, StrLength(#Name)));       \
+    Handle<String> name;                                                     \
+    /* Inline runtime functions have an underscore in front of the name. */  \
+    if (inline_runtime_functions) {                                          \
+      name = Factory::NewStringFromAscii(                                    \
+          Vector<const char>("_" #Name, StrLength("_" #Name)));              \
+    } else {                                                                 \
+      name = Factory::NewStringFromAscii(                                    \
+          Vector<const char>(#Name, StrLength(#Name)));                      \
+    }                                                                        \
     Handle<JSArray> pair = Factory::NewJSArray(0);                           \
     SetElement(pair, 0, name);                                               \
     SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc)));                    \
     SetElement(result, index++, pair);                                       \
   }
+  inline_runtime_functions = false;
   RUNTIME_FUNCTION_LIST(ADD_ENTRY)
+  inline_runtime_functions = true;
+  INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
 #undef ADD_ENTRY
   return *result;
 }
index b10c3f9cf370e76d82ec2c23b1741c62e7e28b77..c8abb66c8cb1abc0604edc79ad32526da5e308b1 100644 (file)
@@ -3600,7 +3600,7 @@ void CodeGenerator::VisitThisFunction(ThisFunction* node) {
 }
 
 
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
 
   // ArgumentsAccessStub expects the key in rdx and the formal
index 8f5fdc172236dfb785d51d88bc721af843d9cf2c..3256cb258ca11f48051e6ace0d6077eff6c8a2e4 100644 (file)
@@ -337,6 +337,10 @@ class CodeGenerator: public AstVisitor {
   bool in_spilled_code() const { return in_spilled_code_; }
   void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
 
+  // If the name is an inline runtime function call return the number of
+  // expected arguments. Otherwise return -1.
+  static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -506,6 +510,7 @@ class CodeGenerator: public AstVisitor {
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
     const char* name;
+    int nargs;
   };
   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
   bool CheckForInlineRuntimeCall(CallRuntime* node);
@@ -537,7 +542,7 @@ class CodeGenerator: public AstVisitor {
 
   // Support for arguments.length and arguments[?].
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
-  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+  void GenerateArguments(ZoneList<Expression*>* args);
 
   // Support for accessing the class and value fields of an object.
   void GenerateClassOf(ZoneList<Expression*>* args);
@@ -575,14 +580,10 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Fast support for Math.pow().
-  void GenerateMathPow(ZoneList<Expression*>* args);
-
   // Fast call to math functions.
+  void GenerateMathPow(ZoneList<Expression*>* args);
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
-
-  // Fast case for sqrt
   void GenerateMathSqrt(ZoneList<Expression*>* args);
 
 // Simple condition analysis.
index 8ea9f7901d50de2c6ddb321a36f57ea42f17103d..6941c4912f33321032f8eb947809e1043cf29acf 100644 (file)
@@ -232,10 +232,12 @@ class CodeGeneratorPatcher {
  public:
   CodeGeneratorPatcher() {
     CodeGenerator::InlineRuntimeLUT genGetFramePointer =
-        {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"};
-    // _FastCharCodeAt is not used in our tests.
+        {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer", 0};
+    // _RandomPositiveSmi is not used in our tests. The one we replace need to
+    // have the same noumer of arguments as the one we put in, which is zero in
+    // this case.
     bool result = CodeGenerator::PatchInlineRuntimeEntry(
-        NewString("_FastCharCodeAt"),
+        NewString("_RandomPositiveSmi"),
         genGetFramePointer, &oldInlineEntry);
     CHECK(result);
   }
index 375038816ab00247013c13b33761497513804e98..ba5970977732194ce1cdba53bff9d32360eac29c 100644 (file)
@@ -57,9 +57,17 @@ function makeFunction(name, argc) {
   return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");");
 }
 
-function testArgumentCount(name) {
+function testArgumentCount(name, argc) {
   for (var i = 0; i < 10; i++) {
-    var func = makeFunction(name, i);
+    var func = null;
+    try {
+      func = makeFunction(name, i);
+    } catch (e) {
+      if (e != "SyntaxError: illegal access") throw e;
+    }
+    if (func === null && i == argc) {
+      throw "unexpected exception";
+    }
     var args = [ ];
     for (var j = 0; j < i; j++)
       args.push(0);
@@ -176,7 +184,7 @@ function testNatives() {
       continue;
     print(name);
     var argc = nativeInfo[1];
-    testArgumentCount(name);
+    testArgumentCount(name, argc);
     testArgumentTypes(name, argc);
   }
 }