| Index: src/runtime.cc
 | 
| ===================================================================
 | 
| --- src/runtime.cc	(revision 3911)
 | 
| +++ src/runtime.cc	(working copy)
 | 
| @@ -49,6 +49,9 @@
 | 
|  namespace v8 {
 | 
|  namespace internal {
 | 
|  
 | 
| +#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
 | 
| +#define DIRECT_CALL_SUPPORTED
 | 
| +#endif
 | 
|  
 | 
|  #define RUNTIME_ASSERT(value) \
 | 
|    if (!(value)) return Top::ThrowIllegalOperation();
 | 
| @@ -487,22 +490,31 @@
 | 
|    return object;
 | 
|  }
 | 
|  
 | 
| -
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_ClassOf(Object* obj) {
 | 
| +  AssertNoAllocation na;
 | 
| +#else
 | 
|  static Object* Runtime_ClassOf(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
|    Object* obj = args[0];
 | 
| +#endif
 | 
|    if (!obj->IsJSObject()) return Heap::null_value();
 | 
|    return JSObject::cast(obj)->class_name();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_IsInPrototypeChain(Object* O, Object* V) {
 | 
| +  AssertNoAllocation na;
 | 
| +#else
 | 
|  static Object* Runtime_IsInPrototypeChain(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
| -  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
 | 
|    Object* O = args[0];
 | 
|    Object* V = args[1];
 | 
| +#endif
 | 
| +  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
 | 
|    while (true) {
 | 
|      Object* prototype = V->GetPrototype();
 | 
|      if (prototype->IsNull()) return Heap::false_value();
 | 
| @@ -624,9 +636,16 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_IsExtensible(Object* arg) {
 | 
| +  AssertNoAllocation na;
 | 
| +  ASSERT(arg->IsJSObject());
 | 
| +  JSObject* obj = JSObject::cast(arg);
 | 
| +#else
 | 
|  static Object* Runtime_IsExtensible(Arguments args) {
 | 
|    ASSERT(args.length() == 1);
 | 
|    CONVERT_CHECKED(JSObject, obj, args[0]);
 | 
| +#endif
 | 
|    return obj->map()->is_extensible() ?  Heap::true_value()
 | 
|                                       : Heap::false_value();
 | 
|  }
 | 
| @@ -1260,21 +1279,39 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_FunctionGetName(Object* arg) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  ASSERT(arg->IsJSFunction());
 | 
| +  JSFunction* f = JSFunction::cast(arg);
 | 
| +#else
 | 
|  static Object* Runtime_FunctionGetName(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
|  
 | 
|    CONVERT_CHECKED(JSFunction, f, args[0]);
 | 
| +#endif
 | 
|    return f->shared()->name();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_FunctionSetName(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  ASSERT(arg0->IsJSFunction());
 | 
| +  JSFunction* f = JSFunction::cast(arg0);
 | 
| +  ASSERT(arg1->IsString());
 | 
| +  String* name = String::cast(arg1);
 | 
| +#else
 | 
|  static Object* Runtime_FunctionSetName(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
|    CONVERT_CHECKED(JSFunction, f, args[0]);
 | 
|    CONVERT_CHECKED(String, name, args[1]);
 | 
| +#endif
 | 
|    f->shared()->set_name(name);
 | 
|    return Heap::undefined_value();
 | 
|  }
 | 
| @@ -2491,12 +2528,19 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_StringLocaleCompare(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +  String* str1 = String::cast(arg0);
 | 
| +  String* str2 = String::cast(arg1);
 | 
| +#else
 | 
|  static Object* Runtime_StringLocaleCompare(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
|    CONVERT_CHECKED(String, str1, args[0]);
 | 
|    CONVERT_CHECKED(String, str2, args[1]);
 | 
| +#endif
 | 
|  
 | 
|    if (str1 == str2) return Smi::FromInt(0);  // Equal.
 | 
|    int str1_length = str1->length();
 | 
| @@ -3538,20 +3582,32 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_ToBool(Object* arg) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  return arg->ToBoolean();
 | 
| +}
 | 
| +#else
 | 
|  static Object* Runtime_ToBool(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
|  
 | 
|    return args[0]->ToBoolean();
 | 
|  }
 | 
| +#endif
 | 
|  
 | 
|  
 | 
|  // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
 | 
|  // Possible optimizations: put the type string into the oddballs.
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_Typeof(Object* obj) {
 | 
| +  AssertNoAllocation na;
 | 
| +#else
 | 
|  static Object* Runtime_Typeof(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
| -
 | 
|    Object* obj = args[0];
 | 
| +#endif
 | 
|    if (obj->IsNumber()) return Heap::number_symbol();
 | 
|    HeapObject* heap_obj = HeapObject::cast(obj);
 | 
|  
 | 
| @@ -4101,11 +4157,16 @@
 | 
|  
 | 
|  // Converts a Number to a Smi, if possible. Returns NaN if the number is not
 | 
|  // a small integer.
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_NumberToSmi(Object* obj) {
 | 
| +  AssertNoAllocation na;
 | 
| +#else
 | 
|  static Object* Runtime_NumberToSmi(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
|  
 | 
|    Object* obj = args[0];
 | 
| +#endif
 | 
|    if (obj->IsSmi()) {
 | 
|      return obj;
 | 
|    }
 | 
| @@ -4401,12 +4462,22 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_NumberEquals(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  ASSERT(arg0->IsNumber());
 | 
| +  double x = arg0->Number();
 | 
| +  ASSERT(arg1->IsNumber());
 | 
| +  double y = arg1->Number();
 | 
| +#else
 | 
|  static Object* Runtime_NumberEquals(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
|    CONVERT_DOUBLE_CHECKED(x, args[0]);
 | 
|    CONVERT_DOUBLE_CHECKED(y, args[1]);
 | 
| +#endif
 | 
|    if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
 | 
|    if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
 | 
|    if (x == y) return Smi::FromInt(EQUAL);
 | 
| @@ -4420,12 +4491,22 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_StringEquals(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  ASSERT(arg0->IsString());
 | 
| +  String* x = String::cast(arg0);
 | 
| +  ASSERT(arg1->IsString());
 | 
| +  String* y = String::cast(arg1);
 | 
| +#else
 | 
|  static Object* Runtime_StringEquals(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
|    CONVERT_CHECKED(String, x, args[0]);
 | 
|    CONVERT_CHECKED(String, y, args[1]);
 | 
| +#endif
 | 
|  
 | 
|    bool not_equal = !x->Equals(y);
 | 
|    // This is slightly convoluted because the value that signifies
 | 
| @@ -4438,6 +4519,16 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_NumberCompare(Object* arg0, Object* arg1, Object* arg2) {
 | 
| +  NoHandleAllocation ha;
 | 
| +
 | 
| +  ASSERT(arg0->IsNumber());
 | 
| +  double x = arg0->Number();
 | 
| +  ASSERT(arg1->IsNumber());
 | 
| +  double y = arg1->Number();
 | 
| +  if (isnan(x) || isnan(y)) return arg2;
 | 
| +#else
 | 
|  static Object* Runtime_NumberCompare(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 3);
 | 
| @@ -4445,6 +4536,7 @@
 | 
|    CONVERT_DOUBLE_CHECKED(x, args[0]);
 | 
|    CONVERT_DOUBLE_CHECKED(y, args[1]);
 | 
|    if (isnan(x) || isnan(y)) return args[2];
 | 
| +#endif
 | 
|    if (x == y) return Smi::FromInt(EQUAL);
 | 
|    if (isless(x, y)) return Smi::FromInt(LESS);
 | 
|    return Smi::FromInt(GREATER);
 | 
| @@ -4453,18 +4545,30 @@
 | 
|  
 | 
|  // Compare two Smis as if they were converted to strings and then
 | 
|  // compared lexicographically.
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_SmiLexicographicCompare(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  // Extract the integer values from the Smis.
 | 
| +  ASSERT(arg0->IsSmi());
 | 
| +  Smi* x = Smi::cast(arg0);
 | 
| +  ASSERT(arg1->IsSmi());
 | 
| +  Smi* y = Smi::cast(arg1);
 | 
| +#else
 | 
|  static Object* Runtime_SmiLexicographicCompare(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
| +  // Extract the integer values from the Smis.
 | 
| +  CONVERT_CHECKED(Smi, x, args[0]);
 | 
| +  CONVERT_CHECKED(Smi, y, args[1]);
 | 
| +#endif
 | 
| +
 | 
|    // Arrays for the individual characters of the two Smis.  Smis are
 | 
|    // 31 bit integers and 10 decimal digits are therefore enough.
 | 
|    static int x_elms[10];
 | 
|    static int y_elms[10];
 | 
|  
 | 
| -  // Extract the integer values from the Smis.
 | 
| -  CONVERT_CHECKED(Smi, x, args[0]);
 | 
| -  CONVERT_CHECKED(Smi, y, args[1]);
 | 
|    int x_value = x->value();
 | 
|    int y_value = y->value();
 | 
|  
 | 
| @@ -4511,12 +4615,22 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_StringCompare(Object* arg0, Object* arg1) {
 | 
| +  AssertNoAllocation na;
 | 
| +
 | 
| +  ASSERT(arg0->IsString());
 | 
| +  String* x = String::cast(arg0);
 | 
| +  ASSERT(arg1->IsString());
 | 
| +  String* y = String::cast(arg1);
 | 
| +#else
 | 
|  static Object* Runtime_StringCompare(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 2);
 | 
|  
 | 
|    CONVERT_CHECKED(String, x, args[0]);
 | 
|    CONVERT_CHECKED(String, y, args[1]);
 | 
| +#endif
 | 
|  
 | 
|    Counters::string_compare_runtime.Increment();
 | 
|  
 | 
| @@ -5457,11 +5571,18 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +#ifdef DIRECT_CALL_SUPPORTED
 | 
| +static Object* Runtime_NumberIsFinite(Object* arg0) {
 | 
| +  AssertNoAllocation na;
 | 
| +  ASSERT(arg0->IsNumber());
 | 
| +  double value = arg0->Number();
 | 
| +#else
 | 
|  static Object* Runtime_NumberIsFinite(Arguments args) {
 | 
|    NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
|  
 | 
|    CONVERT_DOUBLE_CHECKED(value, args[0]);
 | 
| +#endif
 | 
|    Object* result;
 | 
|    if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
 | 
|      result = Heap::false_value();
 | 
| @@ -8109,7 +8230,8 @@
 | 
|    Handle<JSArray> result = Factory::NewJSArray(0);
 | 
|    int index = 0;
 | 
|  #define ADD_ENTRY(Name, argc, ressize)                                       \
 | 
| -  {                                                                          \
 | 
| +  if (Runtime::FunctionForId(Runtime::k##Name)->calling_convention !=        \
 | 
| +      Runtime::DIRECT_CALL_NOT_FAILS) {                                      \
 | 
|      HandleScope inner;                                                       \
 | 
|      Handle<String> name =                                                    \
 | 
|        Factory::NewStringFromAscii(                                           \
 | 
| @@ -8141,17 +8263,58 @@
 | 
|    return NULL;
 | 
|  }
 | 
|  
 | 
| +// ----------------------------------------------------------------------------
 | 
| +// Utilities for building the runtime function list
 | 
| +namespace {
 | 
|  
 | 
| +template <size_t kId>
 | 
| +class SignatureTag {
 | 
| +  char a[kId];  // there is a biection between  id and sizeof(SignatureTag<kId>)
 | 
| +};
 | 
| +
 | 
| +
 | 
| +template <size_t signature_tag_size> struct FunctionTraits;
 | 
| +
 | 
| +
 | 
| +#define SIGNATURE_TRAITS(id, signature) \
 | 
| +  SignatureTag<id> GetTag(signature); \
 | 
| +  template <> struct FunctionTraits<sizeof(SignatureTag<id>)>
 | 
| +
 | 
| +SIGNATURE_TRAITS(1, Object* (*)(Arguments)) {
 | 
| +  static const Runtime::CallingConvention conv = Runtime::EXIT_FRAME_CALL;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +SIGNATURE_TRAITS(2, ObjectPair (*)(Arguments)) {
 | 
| +  static const Runtime::CallingConvention conv = Runtime::EXIT_FRAME_CALL;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +SIGNATURE_TRAITS(3, Object* (*)(Object* arg)) {
 | 
| +  static const Runtime::CallingConvention conv = Runtime::DIRECT_CALL_NOT_FAILS;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +SIGNATURE_TRAITS(4, Object* (*)(Object* agr0, Object* arg1)) {
 | 
| +  static const Runtime::CallingConvention conv = Runtime::DIRECT_CALL_NOT_FAILS;
 | 
| +};
 | 
| +
 | 
| +SIGNATURE_TRAITS(5, Object* (*)(Object* arg0, Object* arg1, Object* arg2)) {
 | 
| +  static const Runtime::CallingConvention conv = Runtime::DIRECT_CALL_NOT_FAILS;
 | 
| +};
 | 
| +}
 | 
| +
 | 
|  // ----------------------------------------------------------------------------
 | 
|  // Implementation of Runtime
 | 
|  
 | 
|  #define F(name, nargs, ressize)                                           \
 | 
|    { #name, FUNCTION_ADDR(Runtime_##name), nargs, \
 | 
| -    static_cast<int>(Runtime::k##name), ressize },
 | 
| +    static_cast<int>(Runtime::k##name), ressize, \
 | 
| +    FunctionTraits<sizeof(GetTag(Runtime_##name))>::conv},
 | 
|  
 | 
|  static Runtime::Function Runtime_functions[] = {
 | 
|    RUNTIME_FUNCTION_LIST(F)
 | 
| -  { NULL, NULL, 0, -1, 0 }
 | 
| +  { NULL, NULL, 0, -1, 0, Runtime::EXIT_FRAME_CALL }
 | 
|  };
 | 
|  
 | 
|  #undef F
 | 
| 
 |