diff options
Diffstat (limited to 'src/3rdparty/v8/src/accessors.cc')
-rw-r--r-- | src/3rdparty/v8/src/accessors.cc | 195 |
1 files changed, 146 insertions, 49 deletions
diff --git a/src/3rdparty/v8/src/accessors.cc b/src/3rdparty/v8/src/accessors.cc index 8048738..c2f245c 100644 --- a/src/3rdparty/v8/src/accessors.cc +++ b/src/3rdparty/v8/src/accessors.cc @@ -42,15 +42,11 @@ namespace internal { template <class C> -static C* FindInPrototypeChain(Object* obj, bool* found_it) { - ASSERT(!*found_it); - Heap* heap = HEAP; - while (!Is<C>(obj)) { - if (obj == heap->null_value()) return NULL; - obj = obj->GetPrototype(); +static C* FindInstanceOf(Object* obj) { + for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype()) { + if (Is<C>(cur)) return C::cast(cur); } - *found_it = true; - return C::cast(obj); + return NULL; } @@ -81,10 +77,8 @@ MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) { MaybeObject* Accessors::ArrayGetLength(Object* object, void*) { // Traverse the prototype chain until we reach an array. - bool found_it = false; - JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it); - if (!found_it) return Smi::FromInt(0); - return holder->length(); + JSArray* holder = FindInstanceOf<JSArray>(object); + return holder == NULL ? Smi::FromInt(0) : holder->length(); } @@ -92,15 +86,56 @@ MaybeObject* Accessors::ArrayGetLength(Object* object, void*) { Object* Accessors::FlattenNumber(Object* value) { if (value->IsNumber() || !value->IsJSValue()) return value; JSValue* wrapper = JSValue::cast(value); - ASSERT(Isolate::Current()->context()->global_context()->number_function()-> + ASSERT(Isolate::Current()->context()->native_context()->number_function()-> has_initial_map()); - Map* number_map = Isolate::Current()->context()->global_context()-> + Map* number_map = Isolate::Current()->context()->native_context()-> number_function()->initial_map(); if (wrapper->map() == number_map) return wrapper->value(); return value; } +static MaybeObject* ArraySetLengthObserved(Isolate* isolate, + Handle<JSArray> array, + Handle<Object> new_length_handle) { + List<Handle<String> > indices; + List<Handle<Object> > old_values; + Handle<Object> old_length_handle(array->length(), isolate); + uint32_t old_length = 0; + CHECK(old_length_handle->ToArrayIndex(&old_length)); + uint32_t new_length = 0; + CHECK(new_length_handle->ToArrayIndex(&new_length)); + // TODO(adamk): This loop can be very slow for arrays in dictionary mode. + // Find another way to iterate over arrays with dictionary elements. + for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { + PropertyAttributes attributes = array->GetLocalElementAttribute(i); + if (attributes == ABSENT) continue; + // A non-configurable property will cause the truncation operation to + // stop at this index. + if (attributes == DONT_DELETE) break; + // TODO(adamk): Don't fetch the old value if it's an accessor. + old_values.Add(Object::GetElement(array, i)); + indices.Add(isolate->factory()->Uint32ToString(i)); + } + + MaybeObject* result = array->SetElementsLength(*new_length_handle); + Handle<Object> hresult; + if (!result->ToHandle(&hresult)) return result; + + CHECK(array->length()->ToArrayIndex(&new_length)); + if (old_length != new_length) { + for (int i = 0; i < indices.length(); ++i) { + JSObject::EnqueueChangeRecord( + array, "deleted", indices[i], old_values[i]); + } + JSObject::EnqueueChangeRecord( + array, "updated", isolate->factory()->length_symbol(), + old_length_handle); + } + return *hresult; +} + + MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { Isolate* isolate = object->GetIsolate(); @@ -118,7 +153,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { HandleScope scope(isolate); // Protect raw pointers. - Handle<JSObject> object_handle(object, isolate); + Handle<JSArray> array_handle(JSArray::cast(object), isolate); Handle<Object> value_handle(value, isolate); bool has_exception; @@ -128,7 +163,11 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { if (has_exception) return Failure::Exception(); if (uint32_v->Number() == number_v->Number()) { - return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v); + if (FLAG_harmony_observation && array_handle->map()->is_observed()) { + return ArraySetLengthObserved(isolate, array_handle, uint32_v); + } else { + return array_handle->SetElementsLength(*uint32_v); + } } return isolate->Throw( *isolate->factory()->NewRangeError("invalid_array_length", @@ -448,15 +487,12 @@ const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) { Heap* heap = Isolate::Current()->heap(); - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return heap->undefined_value(); + JSFunction* function = FindInstanceOf<JSFunction>(object); + if (function == NULL) return heap->undefined_value(); while (!function->should_have_prototype()) { - found_it = false; - function = FindInPrototypeChain<JSFunction>(object->GetPrototype(), - &found_it); + function = FindInstanceOf<JSFunction>(function->GetPrototype()); // There has to be one because we hit the getter. - ASSERT(found_it); + ASSERT(function != NULL); } if (!function->has_prototype()) { @@ -477,9 +513,8 @@ MaybeObject* Accessors::FunctionSetPrototype(JSObject* object, Object* value, void*) { Heap* heap = object->GetHeap(); - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return heap->undefined_value(); + JSFunction* function = FindInstanceOf<JSFunction>(object); + if (function == NULL) return heap->undefined_value(); if (!function->should_have_prototype()) { // Since we hit this accessor, object will have no prototype property. return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(), @@ -509,22 +544,20 @@ const AccessorDescriptor Accessors::FunctionPrototype = { MaybeObject* Accessors::FunctionGetLength(Object* object, void*) { - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return Smi::FromInt(0); + JSFunction* function = FindInstanceOf<JSFunction>(object); + if (function == NULL) return Smi::FromInt(0); // Check if already compiled. - if (!function->shared()->is_compiled()) { - // If the function isn't compiled yet, the length is not computed - // correctly yet. Compile it now and return the right length. - HandleScope scope; - Handle<JSFunction> handle(function); - if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { - return Failure::Exception(); - } - return Smi::FromInt(handle->shared()->length()); - } else { + if (function->shared()->is_compiled()) { return Smi::FromInt(function->shared()->length()); } + // If the function isn't compiled yet, the length is not computed correctly + // yet. Compile it now and return the right length. + HandleScope scope; + Handle<JSFunction> handle(function); + if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { + return Smi::FromInt(handle->shared()->length()); + } + return Failure::Exception(); } @@ -541,10 +574,8 @@ const AccessorDescriptor Accessors::FunctionLength = { MaybeObject* Accessors::FunctionGetName(Object* object, void*) { - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return HEAP->undefined_value(); - return holder->shared()->name(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + return holder == NULL ? HEAP->undefined_value() : holder->shared()->name(); } @@ -589,9 +620,8 @@ static MaybeObject* ConstructArgumentsObjectForInlinedFunction( MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { Isolate* isolate = Isolate::Current(); HandleScope scope(isolate); - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return isolate->heap()->undefined_value(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + if (holder == NULL) return isolate->heap()->undefined_value(); Handle<JSFunction> function(holder, isolate); if (function->shared()->native()) return isolate->heap()->null_value(); @@ -727,9 +757,8 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { Isolate* isolate = Isolate::Current(); HandleScope scope(isolate); AssertNoAllocation no_alloc; - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return isolate->heap()->undefined_value(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + if (holder == NULL) return isolate->heap()->undefined_value(); if (holder->shared()->native()) return isolate->heap()->null_value(); Handle<JSFunction> function(holder, isolate); @@ -755,6 +784,9 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { caller = potential_caller; potential_caller = it.next(); } + if (!caller->shared()->native() && potential_caller != NULL) { + caller = potential_caller; + } // If caller is bound, return null. This is compatible with JSC, and // allows us to make bound functions use the strict function map // and its associated throwing caller and arguments. @@ -802,4 +834,69 @@ const AccessorDescriptor Accessors::ObjectPrototype = { 0 }; + +// +// Accessors::MakeModuleExport +// + +static v8::Handle<v8::Value> ModuleGetExport( + v8::Local<v8::String> property, + const v8::AccessorInfo& info) { + JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder())); + Context* context = Context::cast(instance->context()); + ASSERT(context->IsModuleContext()); + int slot = info.Data()->Int32Value(); + Object* value = context->get(slot); + if (value->IsTheHole()) { + Handle<String> name = v8::Utils::OpenHandle(*property); + Isolate* isolate = instance->GetIsolate(); + isolate->ScheduleThrow( + *isolate->factory()->NewReferenceError("not_defined", + HandleVector(&name, 1))); + return v8::Handle<v8::Value>(); + } + return v8::Utils::ToLocal(Handle<Object>(value)); +} + + +static void ModuleSetExport( + v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) { + JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder())); + Context* context = Context::cast(instance->context()); + ASSERT(context->IsModuleContext()); + int slot = info.Data()->Int32Value(); + Object* old_value = context->get(slot); + if (old_value->IsTheHole()) { + Handle<String> name = v8::Utils::OpenHandle(*property); + Isolate* isolate = instance->GetIsolate(); + isolate->ScheduleThrow( + *isolate->factory()->NewReferenceError("not_defined", + HandleVector(&name, 1))); + return; + } + context->set(slot, *v8::Utils::OpenHandle(*value)); +} + + +Handle<AccessorInfo> Accessors::MakeModuleExport( + Handle<String> name, + int index, + PropertyAttributes attributes) { + Factory* factory = name->GetIsolate()->factory(); + Handle<AccessorInfo> info = factory->NewAccessorInfo(); + info->set_property_attributes(attributes); + info->set_all_can_read(true); + info->set_all_can_write(true); + info->set_name(*name); + info->set_data(Smi::FromInt(index)); + Handle<Object> getter = v8::FromCData(&ModuleGetExport); + Handle<Object> setter = v8::FromCData(&ModuleSetExport); + info->set_getter(*getter); + if (!(attributes & ReadOnly)) info->set_setter(*setter); + return info; +} + + } } // namespace v8::internal |