From: dcarney@chromium.org Date: Wed, 22 May 2013 06:35:38 +0000 (+0000) Subject: implement fast ReturnValue setters X-Git-Tag: upstream/4.7.83~14180 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1045d627335d7f595b52ba750d6a7ee6ec25c29c;p=platform%2Fupstream%2Fv8.git implement fast ReturnValue setters R=svenpanne@chromium.org BUG= Review URL: https://codereview.chromium.org/15398008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14738 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8.h b/include/v8.h index 19a8ad8..72737aa 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1879,6 +1879,7 @@ class V8EXPORT Number : public Primitive { public: double Value() const; static Local New(double value); + static Local New(Isolate* isolate, double value); V8_INLINE(static Number* Cast(v8::Value* obj)); private: Number(); @@ -2740,16 +2741,14 @@ class V8EXPORT ReturnValue { // Handle setters V8_INLINE(void Set(const Persistent& handle)); V8_INLINE(void Set(const Handle handle)); - // TODO(dcarney): implement // Fast primitive setters -// V8_INLINE(void Set(Isolate* isolate, bool)); -// V8_INLINE(void Set(Isolate* isolate, float i)); -// V8_INLINE(void Set(Isolate* isolate, double i)); -// V8_INLINE(void Set(Isolate* isolate, int32_t i)); -// V8_INLINE(void Set(Isolate* isolate, uint32_t i)); + V8_INLINE(void Set(Isolate* isolate, bool value)); + V8_INLINE(void Set(Isolate* isolate, double i)); + V8_INLINE(void Set(Isolate* isolate, int32_t i)); + V8_INLINE(void Set(Isolate* isolate, uint32_t i)); // Fast JS primitive setters -// V8_INLINE(void SetNull(Isolate* isolate)); -// V8_INLINE(void SetUndefined(Isolate* isolate)); + V8_INLINE(void SetNull(Isolate* isolate)); + V8_INLINE(void SetUndefined(Isolate* isolate)); private: internal::Object** value_; }; @@ -5141,6 +5140,14 @@ const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; template struct SmiTagging; +template +V8_INLINE(internal::Object* IntToSmi(int value)) { + int smi_shift_bits = kSmiTagSize + kSmiShiftSize; + intptr_t tagged_value = + (static_cast(value) << smi_shift_bits) | kSmiTag; + return reinterpret_cast(tagged_value); +} + // Smi constants for 32-bit systems. template <> struct SmiTagging<4> { static const int kSmiShiftSize = 0; @@ -5150,6 +5157,23 @@ template <> struct SmiTagging<4> { // Throw away top 32 bits and shift down (requires >> to be sign extending). return static_cast(reinterpret_cast(value)) >> shift_bits; } + V8_INLINE(static internal::Object* IntToSmi(int value)) { + return internal::IntToSmi(value); + } + V8_INLINE(static bool IsValidSmi(intptr_t value)) { + // To be representable as an tagged small integer, the two + // most-significant bits of 'value' must be either 00 or 11 due to + // sign-extension. To check this we add 01 to the two + // most-significant bits, and check if the most-significant bit is 0 + // + // CAUTION: The original code below: + // bool result = ((value + 0x40000000) & 0x80000000) == 0; + // may lead to incorrect results according to the C language spec, and + // in fact doesn't work correctly with gcc4.1.1 in some cases: The + // compiler may produce undefined results in case of signed integer + // overflow. The computation must be done w/ unsigned ints. + return static_cast(value + 0x40000000U) < 0x80000000U; + } }; // Smi constants for 64-bit systems. @@ -5161,6 +5185,13 @@ template <> struct SmiTagging<8> { // Shift down and throw away top 32 bits. return static_cast(reinterpret_cast(value) >> shift_bits); } + V8_INLINE(static internal::Object* IntToSmi(int value)) { + return internal::IntToSmi(value); + } + V8_INLINE(static bool IsValidSmi(intptr_t value)) { + // To be representable as a long smi, the value must be a 32-bit integer. + return (value == static_cast(value)); + } }; typedef SmiTagging PlatformSmiTagging; @@ -5225,6 +5256,14 @@ class Internals { return PlatformSmiTagging::SmiToInt(value); } + V8_INLINE(static internal::Object* IntToSmi(int value)) { + return PlatformSmiTagging::IntToSmi(value); + } + + V8_INLINE(static bool IsValidSmi(intptr_t value)) { + return PlatformSmiTagging::IsValidSmi(value); + } + V8_INLINE(static int GetInstanceType(internal::Object* obj)) { typedef internal::Object O; O* map = ReadField(obj, kHeapObjectMapOffset); @@ -5600,6 +5639,7 @@ uint16_t Persistent::WrapperClassId(Isolate* isolate) const { return *reinterpret_cast(addr); } + template ReturnValue::ReturnValue(internal::Object** slot) : value_(slot) {} @@ -5614,6 +5654,51 @@ void ReturnValue::Set(const Handle handle) { } template +void ReturnValue::Set(Isolate* isolate, double i) { + Set(Number::New(isolate, i)); +} + +template +void ReturnValue::Set(Isolate* isolate, int32_t i) { + typedef internal::Internals I; + if (V8_LIKELY(I::IsValidSmi(i))) { + *value_ = I::IntToSmi(i); + return; + } + Set(Integer::New(i, isolate)); +} + +template +void ReturnValue::Set(Isolate* isolate, uint32_t i) { + typedef internal::Internals I; + if (V8_LIKELY(I::IsValidSmi(i))) { + *value_ = I::IntToSmi(i); + return; + } + Set(Integer::NewFromUnsigned(i, isolate)); +} + +template +void ReturnValue::Set(Isolate* isolate, bool value) { + typedef internal::Internals I; + *value_ = *I::GetRoot( + isolate, value ? I::kTrueValueRootIndex : I::kFalseValueRootIndex); +} + +template +void ReturnValue::SetNull(Isolate* isolate) { + typedef internal::Internals I; + *value_ = *I::GetRoot(isolate, I::kNullValueRootIndex); +} + +template +void ReturnValue::SetUndefined(Isolate* isolate) { + typedef internal::Internals I; + *value_ = *I::GetRoot(isolate, I::kUndefinedValueRootIndex); +} + + +template FunctionCallbackInfo::FunctionCallbackInfo(internal::Object** implicit_args, internal::Object** values, int length, diff --git a/src/api.cc b/src/api.cc index ccf3822..7099ca8 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6207,12 +6207,19 @@ Local v8::Symbol::New(Isolate* isolate, const char* data, int length) { Local v8::Number::New(double value) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Number::New()"); + return Number::New(reinterpret_cast(isolate), value); +} + + +Local v8::Number::New(Isolate* isolate, double value) { + i::Isolate* internal_isolate = reinterpret_cast(isolate); + ASSERT(internal_isolate->IsInitialized()); if (std::isnan(value)) { // Introduce only canonical NaN value into the VM, to avoid signaling NaNs. value = i::OS::nan_value(); } - ENTER_V8(isolate); - i::Handle result = isolate->factory()->NewNumber(value); + ENTER_V8(internal_isolate); + i::Handle result = internal_isolate->factory()->NewNumber(value); return Utils::NumberToLocal(result); } diff --git a/src/objects-inl.h b/src/objects-inl.h index c48876b..40cb1fd 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1030,10 +1030,7 @@ int Smi::value() { Smi* Smi::FromInt(int value) { ASSERT(Smi::IsValid(value)); - int smi_shift_bits = kSmiTagSize + kSmiShiftSize; - intptr_t tagged_value = - (static_cast(value) << smi_shift_bits) | kSmiTag; - return reinterpret_cast(tagged_value); + return reinterpret_cast(Internals::IntToSmi(value)); } @@ -1111,28 +1108,8 @@ Failure* Failure::Construct(Type type, intptr_t value) { bool Smi::IsValid(intptr_t value) { -#ifdef DEBUG - bool in_range = (value >= kMinValue) && (value <= kMaxValue); -#endif - -#ifdef V8_TARGET_ARCH_X64 - // To be representable as a long smi, the value must be a 32-bit integer. - bool result = (value == static_cast(value)); -#else - // To be representable as an tagged small integer, the two - // most-significant bits of 'value' must be either 00 or 11 due to - // sign-extension. To check this we add 01 to the two - // most-significant bits, and check if the most-significant bit is 0 - // - // CAUTION: The original code below: - // bool result = ((value + 0x40000000) & 0x80000000) == 0; - // may lead to incorrect results according to the C language spec, and - // in fact doesn't work correctly with gcc4.1.1 in some cases: The - // compiler may produce undefined results in case of signed integer - // overflow. The computation must be done w/ unsigned ints. - bool result = (static_cast(value + 0x40000000U) < 0x80000000U); -#endif - ASSERT(result == in_range); + bool result = Internals::IsValidSmi(value); + ASSERT_EQ(result, value >= kMinValue && value <= kMaxValue); return result; } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index b4f962c..c8f67de 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -1010,6 +1010,98 @@ THREADED_TEST(SimpleCallback) { } +template +void FastReturnValueCallback(const v8::FunctionCallbackInfo& info); + +// constant return values +static const int32_t kFastReturnValueInt32 = 471; +static const uint32_t kFastReturnValueUint32 = 571; +static const double kFastReturnValueDouble = 2.7; +// variable return values +static bool fast_return_value_bool = false; +static bool fast_return_value_void_is_null = false; + +template<> +void FastReturnValueCallback( + const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(info.GetIsolate(), kFastReturnValueInt32); +} + +template<> +void FastReturnValueCallback( + const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(info.GetIsolate(), kFastReturnValueUint32); +} + +template<> +void FastReturnValueCallback( + const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(info.GetIsolate(), kFastReturnValueDouble); +} + +template<> +void FastReturnValueCallback( + const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(info.GetIsolate(), fast_return_value_bool); +} + +template<> +void FastReturnValueCallback( + const v8::FunctionCallbackInfo& info) { + if (fast_return_value_void_is_null) { + info.GetReturnValue().SetNull(info.GetIsolate()); + } else { + info.GetReturnValue().SetUndefined(info.GetIsolate()); + } +} + +template +Handle TestFastReturnValues() { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::Handle object_template = v8::ObjectTemplate::New(); + v8::FunctionCallback callback = &FastReturnValueCallback; + object_template->Set("callback", v8::FunctionTemplate::New(callback)); + v8::Local object = object_template->NewInstance(); + (*env)->Global()->Set(v8_str("callback_object"), object); + return scope.Close(CompileRun("callback_object.callback()")); +} + +THREADED_TEST(FastReturnValues) { + v8::HandleScope scope(v8::Isolate::GetCurrent()); + v8::Handle value; + // check int_32 + value = TestFastReturnValues(); + CHECK(value->IsInt32()); + CHECK_EQ(kFastReturnValueInt32, value->Int32Value()); + // check uint32_t + value = TestFastReturnValues(); + CHECK(value->IsInt32()); + CHECK_EQ(kFastReturnValueUint32, value->Int32Value()); + // check double + value = TestFastReturnValues(); + CHECK(value->IsNumber()); + CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value()); + // check bool values + for (int i = 0; i < 2; i++) { + fast_return_value_bool = i == 0; + value = TestFastReturnValues(); + CHECK(value->IsBoolean()); + CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value()); + } + // check oddballs + for (int i = 0; i < 2; i++) { + fast_return_value_void_is_null = i == 0; + value = TestFastReturnValues(); + if (fast_return_value_void_is_null) { + CHECK(value->IsNull()); + } else { + CHECK(value->IsUndefined()); + } + } +} + + THREADED_TEST(FunctionTemplateSetLength) { LocalContext env; v8::HandleScope scope(env->GetIsolate());