From 5d0d354e09c31ec74767a27b9ba732009e3f583b Mon Sep 17 00:00:00 2001 From: "feng@chromium.org" Date: Mon, 8 Sep 2008 16:47:23 +0000 Subject: [PATCH] Fix issue http://code.google.com/p/v8/issues/detail?id=32 Allows numberical strings as array index and make a call. e.g., callbacks['0'](); Added more test case for regexp (disabled by default, requires --call_regexp) and call_as_function object created by API. Review URL: http://codereview.chromium.org/1604 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@214 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ic.cc | 58 +++++++++++++++++++++----------- src/ic.h | 5 +++ test/cctest/test-api.cc | 5 +++ test/mjsunit/number-string-index-call.js | 32 ++++++++++++++++++ 4 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 test/mjsunit/number-string-index-call.js diff --git a/src/ic.cc b/src/ic.cc index 2074a76..1dd288d 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -250,6 +250,26 @@ void KeyedStoreIC::Clear(Address address, Code* target) { } +Object* CallIC::TryCallAsFunction(Object* object) { + HandleScope scope; + Handle target(object); + Handle delegate = Execution::GetFunctionDelegate(target); + + if (delegate->IsJSFunction()) { + // Patch the receiver and use the delegate as the function to + // invoke. This is used for invoking objects as if they were + // functions. + const int argc = this->target()->arguments_count(); + StackFrameLocator locator; + JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); + int index = frame->ComputeExpressionsCount() - (argc + 1); + frame->SetExpression(index, *target); + } + + return *delegate; +} + + Object* CallIC::LoadFunction(State state, Handle object, Handle name) { @@ -259,12 +279,26 @@ Object* CallIC::LoadFunction(State state, return TypeError("non_object_property_call", object, name); } + Object* result = Heap::the_hole_value(); + + // Check if the name is trivially convertible to an index and get + // the element if so. + uint32_t index; + if (name->AsArrayIndex(&index)) { + result = object->GetElement(index); + if (result->IsJSFunction()) return result; + + // Try to find a suitable function delegate for the object at hand. + result = TryCallAsFunction(result); + if (result->IsJSFunction()) return result; + + // Otherwise, it will fail in the lookup step. + } + // Lookup the property in the object. LookupResult lookup; object->Lookup(*name, &lookup); - Object* result = Heap::the_hole_value(); - if (!lookup.IsValid()) { // If the object does not have the requested property, check which // exception we need to throw. @@ -328,23 +362,9 @@ Object* CallIC::LoadFunction(State state, } // Try to find a suitable function delegate for the object at hand. - HandleScope scope; - Handle target(result); - Handle delegate = Execution::GetFunctionDelegate(target); - - if (delegate->IsJSFunction()) { - // Patch the receiver and use the delegate as the function to - // invoke. This is used for invoking objects as if they were - // functions. - const int argc = this->target()->arguments_count(); - StackFrameLocator locator; - JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); - int index = frame->ComputeExpressionsCount() - (argc + 1); - frame->SetExpression(index, *target); - return *delegate; - } else { - return TypeError("property_not_function", object, name); - } + result = TryCallAsFunction(result); + return result->IsJSFunction() ? + result : TypeError("property_not_function", object, name); } diff --git a/src/ic.h b/src/ic.h index b474e9f..ebd3407 100644 --- a/src/ic.h +++ b/src/ic.h @@ -183,6 +183,11 @@ class CallIC: public IC { Handle object, Handle name); + // Returns a JSFunction if the object can be called as a function, + // and patches the stack to be ready for the call. + // Otherwise, it returns the undefined value. + Object* TryCallAsFunction(Object* object); + static void Clear(Address address, Code* target); friend class IC; }; diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 052a6c8..d70fd8e 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -3959,6 +3959,11 @@ THREADED_TEST(CallAsFunction) { CHECK(!try_catch.HasCaught()); CHECK_EQ(49, value->Int32Value()); + // test special case of call as function + value = Script::Compile(v8_str("[obj]['0'](45)"))->Run(); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(45, value->Int32Value()); + value = Script::Compile(v8_str("obj.call = Function.prototype.call;" "obj.call(null, 87)"))->Run(); CHECK(!try_catch.HasCaught()); diff --git a/test/mjsunit/number-string-index-call.js b/test/mjsunit/number-string-index-call.js new file mode 100644 index 0000000..28d87fb --- /dev/null +++ b/test/mjsunit/number-string-index-call.js @@ -0,0 +1,32 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --call_regexp +var callbacks = [ function() {return 'foo'}, "nonobject", /abc/ ]; +assertEquals('foo', callbacks['0']()); +assertThrows("callbacks['1']()"); +assertEquals('abc', callbacks['2']("abcdefg")); -- 2.7.4