diff options
Diffstat (limited to 'V8Binding/v8/src/runtime.cc')
-rw-r--r-- | V8Binding/v8/src/runtime.cc | 223 |
1 files changed, 137 insertions, 86 deletions
diff --git a/V8Binding/v8/src/runtime.cc b/V8Binding/v8/src/runtime.cc index c26783a..4e1940d 100644 --- a/V8Binding/v8/src/runtime.cc +++ b/V8Binding/v8/src/runtime.cc @@ -1208,6 +1208,14 @@ static Object* Runtime_FunctionIsAPIFunction(Arguments args) { : Heap::false_value(); } +static Object* Runtime_FunctionIsBuiltin(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 1); + + CONVERT_CHECKED(JSFunction, f, args[0]); + return f->IsBuiltin() ? Heap::true_value() : Heap::false_value(); +} + static Object* Runtime_SetCode(Arguments args) { HandleScope scope; @@ -2992,7 +3000,8 @@ static Object* Runtime_GetPropertyNamesFast(Arguments args) { HandleScope scope; Handle<JSObject> object(raw_object); - Handle<FixedArray> content = GetKeysInFixedArrayFor(object); + Handle<FixedArray> content = GetKeysInFixedArrayFor(object, + INCLUDE_PROTOS); // Test again, since cache may have been built by preceding call. if (object->IsSimpleEnum()) return object->map(); @@ -3001,6 +3010,34 @@ static Object* Runtime_GetPropertyNamesFast(Arguments args) { } +static Object* Runtime_LocalKeys(Arguments args) { + ASSERT_EQ(args.length(), 1); + CONVERT_CHECKED(JSObject, raw_object, args[0]); + HandleScope scope; + Handle<JSObject> object(raw_object); + Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, + LOCAL_ONLY); + // Some fast paths through GetKeysInFixedArrayFor reuse a cached + // property array and since the result is mutable we have to create + // a fresh clone on each invocation. + int length = contents->length(); + Handle<FixedArray> copy = Factory::NewFixedArray(length); + for (int i = 0; i < length; i++) { + Object* entry = contents->get(i); + if (entry->IsString()) { + copy->set(i, entry); + } else { + ASSERT(entry->IsNumber()); + HandleScope scope; + Handle<Object> entry_handle(entry); + Handle<Object> entry_str = Factory::NumberToString(entry_handle); + copy->set(i, *entry_str); + } + } + return *Factory::NewJSArrayWithElements(copy); +} + + static Object* Runtime_GetArgumentsProperty(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 1); @@ -3562,27 +3599,7 @@ static Object* Runtime_NumberToString(Arguments args) { Object* number = args[0]; RUNTIME_ASSERT(number->IsNumber()); - Object* cached = Heap::GetNumberStringCache(number); - if (cached != Heap::undefined_value()) { - return cached; - } - - char arr[100]; - Vector<char> buffer(arr, ARRAY_SIZE(arr)); - const char* str; - if (number->IsSmi()) { - int num = Smi::cast(number)->value(); - str = IntToCString(num, buffer); - } else { - double num = HeapNumber::cast(number)->value(); - str = DoubleToCString(num, buffer); - } - Object* result = Heap::AllocateStringFromAscii(CStrVector(str)); - - if (!result->IsFailure()) { - Heap::SetNumberStringCache(number, String::cast(result)); - } - return result; + return Heap::NumberToString(number); } @@ -3696,7 +3713,7 @@ static Object* Runtime_NumberMod(Arguments args) { CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(y, args[1]); -#ifdef WIN32 +#if defined WIN32 || defined _WIN64 // Workaround MS fmod bugs. ECMA-262 says: // dividend is finite and divisor is an infinity => result equals dividend // dividend is a zero and divisor is nonzero finite => result equals dividend @@ -4556,22 +4573,25 @@ static Object* Runtime_LookupContext(Arguments args) { } -// A mechanism to return pairs of Object*'s. This is somewhat -// compiler-dependent as it assumes that a 64-bit value (a long long) -// is returned via two registers (edx:eax on ia32). Both the ia32 and -// arm platform support this; it is mostly an issue of "coaxing" the -// compiler to do the right thing. -// -// TODO(1236026): This is a non-portable hack that should be removed. +// A mechanism to return a pair of Object pointers in registers (if possible). +// How this is achieved is calling convention-dependent. +// All currently supported x86 compiles uses calling conventions that are cdecl +// variants where a 64-bit value is returned in two 32-bit registers +// (edx:eax on ia32, r1:r0 on ARM). +// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. +// In Win64 calling convention, a struct of two pointers is returned in memory, +// allocated by the caller, and passed as a pointer in a hidden first parameter. #ifdef V8_HOST_ARCH_64_BIT -// Tested with GCC, not with MSVC. struct ObjectPair { Object* x; Object* y; }; + static inline ObjectPair MakePair(Object* x, Object* y) { ObjectPair result = {x, y}; - return result; // Pointers x and y returned in rax and rdx, in AMD-x64-abi. + // Pointers x and y returned in rax and rdx, in AMD-x64-abi. + // In Win64 they are assigned to a hidden first argument. + return result; } #else typedef uint64_t ObjectPair; @@ -4582,8 +4602,6 @@ static inline ObjectPair MakePair(Object* x, Object* y) { #endif - - static inline Object* Unhole(Object* x, PropertyAttributes attributes) { ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); USE(attributes); @@ -5515,7 +5533,7 @@ static Object* Runtime_GetArrayKeys(Arguments args) { if (array->elements()->IsDictionary()) { // Create an array and get all the keys into it, then remove all the // keys that are not integers in the range 0 to length-1. - Handle<FixedArray> keys = GetKeysInFixedArrayFor(array); + Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS); int keys_length = keys->length(); for (int i = 0; i < keys_length; i++) { Object* key = keys->get(i); @@ -5737,55 +5755,51 @@ static Object* Runtime_DebugGetPropertyDetails(Arguments args) { int length = LocalPrototypeChainLength(*obj); // Try local lookup on each of the objects. - LookupResult result; Handle<JSObject> jsproto = obj; for (int i = 0; i < length; i++) { + LookupResult result; jsproto->LocalLookup(*name, &result); if (result.IsProperty()) { - break; + // LookupResult is not GC safe as it holds raw object pointers. + // GC can happen later in this code so put the required fields into + // local variables using handles when required for later use. + PropertyType result_type = result.type(); + Handle<Object> result_callback_obj; + if (result_type == CALLBACKS) { + result_callback_obj = Handle<Object>(result.GetCallbackObject()); + } + Smi* property_details = result.GetPropertyDetails().AsSmi(); + // DebugLookupResultValue can cause GC so details from LookupResult needs + // to be copied to handles before this. + bool caught_exception = false; + Object* raw_value = DebugLookupResultValue(*obj, *name, &result, + &caught_exception); + if (raw_value->IsFailure()) return raw_value; + Handle<Object> value(raw_value); + + // If the callback object is a fixed array then it contains JavaScript + // getter and/or setter. + bool hasJavaScriptAccessors = result_type == CALLBACKS && + result_callback_obj->IsFixedArray(); + Handle<FixedArray> details = + Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2); + details->set(0, *value); + details->set(1, property_details); + if (hasJavaScriptAccessors) { + details->set(2, + caught_exception ? Heap::true_value() + : Heap::false_value()); + details->set(3, FixedArray::cast(*result_callback_obj)->get(0)); + details->set(4, FixedArray::cast(*result_callback_obj)->get(1)); + } + + return *Factory::NewJSArrayWithElements(details); } if (i < length - 1) { jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); } } - if (result.IsProperty()) { - // LookupResult is not GC safe as all its members are raw object pointers. - // When calling DebugLookupResultValue GC can happen as this might invoke - // callbacks. After the call to DebugLookupResultValue the callback object - // in the LookupResult might still be needed. Put it into a handle for later - // use. - PropertyType result_type = result.type(); - Handle<Object> result_callback_obj; - if (result_type == CALLBACKS) { - result_callback_obj = Handle<Object>(result.GetCallbackObject()); - } - - // Find the actual value. Don't use result after this call as it's content - // can be invalid. - bool caught_exception = false; - Object* value = DebugLookupResultValue(*obj, *name, &result, - &caught_exception); - if (value->IsFailure()) return value; - Handle<Object> value_handle(value); - - // If the callback object is a fixed array then it contains JavaScript - // getter and/or setter. - bool hasJavaScriptAccessors = result_type == CALLBACKS && - result_callback_obj->IsFixedArray(); - Handle<FixedArray> details = - Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2); - details->set(0, *value_handle); - details->set(1, result.GetPropertyDetails().AsSmi()); - if (hasJavaScriptAccessors) { - details->set(2, - caught_exception ? Heap::true_value() : Heap::false_value()); - details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0)); - details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1)); - } - - return *Factory::NewJSArrayWithElements(details); - } return Heap::undefined_value(); } @@ -6270,7 +6284,7 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) { if (function_context->has_extension() && !function_context->IsGlobalContext()) { Handle<JSObject> ext(JSObject::cast(function_context->extension())); - Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext); + Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); for (int i = 0; i < keys->length(); i++) { // Names of variables introduced by eval are strings. ASSERT(keys->get(i)->IsString()); @@ -6319,7 +6333,7 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) { // be variables introduced by eval. if (context->has_extension()) { Handle<JSObject> ext(JSObject::cast(context->extension())); - Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext); + Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); for (int i = 0; i < keys->length(); i++) { // Names of variables introduced by eval are strings. ASSERT(keys->get(i)->IsString()); @@ -6341,7 +6355,12 @@ class ScopeIterator { ScopeTypeGlobal = 0, ScopeTypeLocal, ScopeTypeWith, - ScopeTypeClosure + ScopeTypeClosure, + // Every catch block contains an implicit with block (its parameter is + // a JSContextExtensionObject) that extends current scope with a variable + // holding exception object. Such with blocks are treated as scopes of their + // own type. + ScopeTypeCatch }; explicit ScopeIterator(JavaScriptFrame* frame) @@ -6417,7 +6436,14 @@ class ScopeIterator { return ScopeTypeClosure; } ASSERT(context_->has_extension()); - ASSERT(!context_->extension()->IsJSContextExtensionObject()); + // Current scope is either an explicit with statement or a with statement + // implicitely generated for a catch block. + // If the extension object here is a JSContextExtensionObject then + // current with statement is one frome a catch block otherwise it's a + // regular with statement. + if (context_->extension()->IsJSContextExtensionObject()) { + return ScopeTypeCatch; + } return ScopeTypeWith; } @@ -6432,6 +6458,7 @@ class ScopeIterator { return MaterializeLocalScope(frame_); break; case ScopeIterator::ScopeTypeWith: + case ScopeIterator::ScopeTypeCatch: // Return the with object. return Handle<JSObject>(CurrentContext()->extension()); break; @@ -6488,6 +6515,14 @@ class ScopeIterator { break; } + case ScopeIterator::ScopeTypeCatch: { + PrintF("Catch:\n"); + Handle<JSObject> extension = + Handle<JSObject>(CurrentContext()->extension()); + extension->Print(); + break; + } + case ScopeIterator::ScopeTypeClosure: { PrintF("Closure:\n"); CurrentContext()->Print(); @@ -6799,8 +6834,20 @@ Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script, target_start_position = start_position; target = shared; } else { - if (target_start_position < start_position && - shared->end_position() < target->end_position()) { + if (target_start_position == start_position && + shared->end_position() == target->end_position()) { + // If a top-level function contain only one function + // declartion the source for the top-level and the function is + // the same. In that case prefer the non top-level function. + if (!shared->is_toplevel()) { + target_start_position = start_position; + target = shared; + } + } else if (target_start_position <= start_position && + shared->end_position() <= target->end_position()) { + // This containment check includes equality as a function inside + // a top-level function can share either start or end position + // with the top-level function. target_start_position = start_position; target = shared; } @@ -6912,7 +6959,8 @@ static Object* Runtime_ChangeBreakOnException(Arguments args) { // Prepare for stepping // args[0]: break id for checking execution state // args[1]: step action from the enumeration StepAction -// args[2]: number of times to perform the step +// args[2]: number of times to perform the step, for step out it is the number +// of frames to step down. static Object* Runtime_PrepareStep(Arguments args) { HandleScope scope; ASSERT(args.length() == 3); @@ -6939,6 +6987,9 @@ static Object* Runtime_PrepareStep(Arguments args) { return Top::Throw(Heap::illegal_argument_symbol()); } + // Clear all current stepping setup. + Debug::ClearStepping(); + // Prepare step. Debug::PrepareStep(static_cast<StepAction>(step_action), step_count); return Heap::undefined_value(); @@ -7089,7 +7140,7 @@ static Object* Runtime_DebugEvaluate(Arguments args) { // the function being debugged. // function(arguments,__source__) {return eval(__source__);} static const char* source_str = - "function(arguments,__source__){return eval(__source__);}"; + "(function(arguments,__source__){return eval(__source__);})"; static const int source_str_length = strlen(source_str); Handle<String> function_source = Factory::NewStringFromAscii(Vector<const char>(source_str, @@ -7598,7 +7649,7 @@ static Object* Runtime_ListNatives(Arguments args) { HandleScope scope; Handle<JSArray> result = Factory::NewJSArray(0); int index = 0; -#define ADD_ENTRY(Name, argc) \ +#define ADD_ENTRY(Name, argc, ressize) \ { \ HandleScope inner; \ Handle<String> name = \ @@ -7634,13 +7685,13 @@ static Object* Runtime_IS_VAR(Arguments args) { // ---------------------------------------------------------------------------- // Implementation of Runtime -#define F(name, nargs) \ +#define F(name, nargs, ressize) \ { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \ - static_cast<int>(Runtime::k##name) }, + static_cast<int>(Runtime::k##name), ressize }, static Runtime::Function Runtime_functions[] = { RUNTIME_FUNCTION_LIST(F) - { NULL, NULL, NULL, 0, -1 } + { NULL, NULL, NULL, 0, -1, 0 } }; #undef F |