diff options
Diffstat (limited to 'chromium/v8/src/accessors.cc')
-rw-r--r-- | chromium/v8/src/accessors.cc | 1378 |
1 files changed, 881 insertions, 497 deletions
diff --git a/chromium/v8/src/accessors.cc b/chromium/v8/src/accessors.cc index 4da9dd44ffe..54bd241b8d6 100644 --- a/chromium/v8/src/accessors.cc +++ b/chromium/v8/src/accessors.cc @@ -1,88 +1,84 @@ // Copyright 2012 the V8 project authors. 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. - -#include "v8.h" -#include "accessors.h" - -#include "contexts.h" -#include "deoptimizer.h" -#include "execution.h" -#include "factory.h" -#include "frames-inl.h" -#include "isolate.h" -#include "list-inl.h" -#include "property-details.h" +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" +#include "src/accessors.h" + +#include "src/compiler.h" +#include "src/contexts.h" +#include "src/deoptimizer.h" +#include "src/execution.h" +#include "src/factory.h" +#include "src/frames-inl.h" +#include "src/isolate.h" +#include "src/list-inl.h" +#include "src/property-details.h" +#include "src/api.h" namespace v8 { namespace internal { -template <class C> -static C* FindInstanceOf(Isolate* isolate, Object* obj) { - for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) { - if (Is<C>(cur)) return C::cast(cur); - } - return NULL; +// We have a slight impedance mismatch between the external API and the way we +// use callbacks internally: Externally, callbacks can only be used with +// v8::Object, but internally we even have callbacks on entities which are +// higher in the hierarchy, so we can only return i::Object here, not +// i::JSObject. +Handle<Object> GetThisFrom(const v8::PropertyCallbackInfo<v8::Value>& info) { + return Utils::OpenHandle(*v8::Local<v8::Value>(info.This())); } -// Entry point that never should be called. -MaybeObject* Accessors::IllegalSetter(Isolate* isolate, - JSObject*, - Object*, - void*) { - UNREACHABLE(); - return NULL; +Handle<AccessorInfo> Accessors::MakeAccessor( + Isolate* isolate, + Handle<String> name, + AccessorGetterCallback getter, + AccessorSetterCallback setter, + PropertyAttributes attributes) { + Factory* factory = isolate->factory(); + Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo(); + info->set_property_attributes(attributes); + info->set_all_can_read(false); + info->set_all_can_write(false); + info->set_name(*name); + Handle<Object> get = v8::FromCData(isolate, getter); + Handle<Object> set = v8::FromCData(isolate, setter); + info->set_getter(*get); + info->set_setter(*set); + return info; } -Object* Accessors::IllegalGetAccessor(Isolate* isolate, - Object* object, - void*) { - UNREACHABLE(); - return object; +Handle<ExecutableAccessorInfo> Accessors::CloneAccessor( + Isolate* isolate, + Handle<ExecutableAccessorInfo> accessor) { + Factory* factory = isolate->factory(); + Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo(); + info->set_name(accessor->name()); + info->set_flag(accessor->flag()); + info->set_expected_receiver_type(accessor->expected_receiver_type()); + info->set_getter(accessor->getter()); + info->set_setter(accessor->setter()); + info->set_data(accessor->data()); + return info; } -MaybeObject* Accessors::ReadOnlySetAccessor(Isolate* isolate, - JSObject*, - Object* value, - void*) { - // According to ECMA-262, section 8.6.2.2, page 28, setting - // read-only properties must be silently ignored. - return value; +template <class C> +static C* FindInstanceOf(Isolate* isolate, Object* obj) { + for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) { + if (Is<C>(cur)) return C::cast(cur); + } + return NULL; } static V8_INLINE bool CheckForName(Handle<String> name, - String* property_name, + Handle<String> property_name, int offset, int* object_offset) { - if (name->Equals(property_name)) { + if (String::Equals(name, property_name)) { *object_offset = offset; return true; } @@ -90,63 +86,68 @@ static V8_INLINE bool CheckForName(Handle<String> name, } -bool Accessors::IsJSObjectFieldAccessor( - Handle<Map> map, Handle<String> name, - int* object_offset) { - Isolate* isolate = map->GetIsolate(); +// Returns true for properties that are accessors to object fields. +// If true, *object_offset contains offset of object field. +template <class T> +bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type, + Handle<String> name, + int* object_offset) { + Isolate* isolate = name->GetIsolate(); + + if (type->Is(T::String())) { + return CheckForName(name, isolate->factory()->length_string(), + String::kLengthOffset, object_offset); + } + + if (!type->IsClass()) return false; + Handle<Map> map = type->AsClass()->Map(); + switch (map->instance_type()) { case JS_ARRAY_TYPE: return - CheckForName(name, isolate->heap()->length_string(), + CheckForName(name, isolate->factory()->length_string(), JSArray::kLengthOffset, object_offset); case JS_TYPED_ARRAY_TYPE: return - CheckForName(name, isolate->heap()->length_string(), + CheckForName(name, isolate->factory()->length_string(), JSTypedArray::kLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSTypedArray::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_offset_string(), - JSTypedArray::kByteOffsetOffset, object_offset) || - CheckForName(name, isolate->heap()->buffer_string(), - JSTypedArray::kBufferOffset, object_offset); + CheckForName(name, isolate->factory()->byte_offset_string(), + JSTypedArray::kByteOffsetOffset, object_offset); case JS_ARRAY_BUFFER_TYPE: return - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSArrayBuffer::kByteLengthOffset, object_offset); case JS_DATA_VIEW_TYPE: return - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSDataView::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_offset_string(), - JSDataView::kByteOffsetOffset, object_offset) || - CheckForName(name, isolate->heap()->buffer_string(), - JSDataView::kBufferOffset, object_offset); - default: { - if (map->instance_type() < FIRST_NONSTRING_TYPE) { - return - CheckForName(name, isolate->heap()->length_string(), - String::kLengthOffset, object_offset); - } + CheckForName(name, isolate->factory()->byte_offset_string(), + JSDataView::kByteOffsetOffset, object_offset); + default: return false; - } } } +template +bool Accessors::IsJSObjectFieldAccessor<Type>(Type* type, + Handle<String> name, + int* object_offset); + + +template +bool Accessors::IsJSObjectFieldAccessor<HeapType>(Handle<HeapType> type, + Handle<String> name, + int* object_offset); + + // // Accessors::ArrayLength // -MaybeObject* Accessors::ArrayGetLength(Isolate* isolate, - Object* object, - void*) { - // Traverse the prototype chain until we reach an array. - JSArray* holder = FindInstanceOf<JSArray>(isolate, object); - return holder == NULL ? Smi::FromInt(0) : holder->length(); -} - - // The helper function will 'flatten' Number objects. Handle<Object> Accessors::FlattenNumber(Isolate* isolate, Handle<Object> value) { @@ -163,114 +164,162 @@ Handle<Object> Accessors::FlattenNumber(Isolate* isolate, } -MaybeObject* Accessors::ArraySetLength(Isolate* isolate, - JSObject* object_raw, - Object* value_raw, - void*) { +void Accessors::ArrayLengthGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; HandleScope scope(isolate); - Handle<JSObject> object(object_raw, isolate); - Handle<Object> value(value_raw, isolate); + Object* object = *GetThisFrom(info); + // Traverse the prototype chain until we reach an array. + JSArray* holder = FindInstanceOf<JSArray>(isolate, object); + Object* result; + if (holder != NULL) { + result = holder->length(); + } else { + result = Smi::FromInt(0); + } + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); +} + +void Accessors::ArrayLengthSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<JSObject> object = Handle<JSObject>::cast( + Utils::OpenHandle(*info.This())); + Handle<Object> value = Utils::OpenHandle(*val); // This means one of the object's prototypes is a JSArray and the // object does not have a 'length' property. Calling SetProperty // causes an infinite loop. if (!object->IsJSArray()) { - Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object, - isolate->factory()->length_string(), value, NONE); - RETURN_IF_EMPTY_HANDLE(isolate, result); - return *result; + MaybeHandle<Object> maybe_result = + JSObject::SetOwnPropertyIgnoreAttributes( + object, isolate->factory()->length_string(), value, NONE); + maybe_result.Check(); + return; } value = FlattenNumber(isolate, value); Handle<JSArray> array_handle = Handle<JSArray>::cast(object); - - bool has_exception; - Handle<Object> uint32_v = - Execution::ToUint32(isolate, value, &has_exception); - if (has_exception) return Failure::Exception(); - Handle<Object> number_v = - Execution::ToNumber(isolate, value, &has_exception); - if (has_exception) return Failure::Exception(); + MaybeHandle<Object> maybe; + Handle<Object> uint32_v; + maybe = Execution::ToUint32(isolate, value); + if (!maybe.ToHandle(&uint32_v)) { + isolate->OptionalRescheduleException(false); + return; + } + Handle<Object> number_v; + maybe = Execution::ToNumber(isolate, value); + if (!maybe.ToHandle(&number_v)) { + isolate->OptionalRescheduleException(false); + return; + } if (uint32_v->Number() == number_v->Number()) { - return array_handle->SetElementsLength(*uint32_v); + maybe = JSArray::SetElementsLength(array_handle, uint32_v); + maybe.Check(); + return; } - return isolate->Throw( + + isolate->ScheduleThrow( *isolate->factory()->NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0))); } -const AccessorDescriptor Accessors::ArrayLength = { - ArrayGetLength, - ArraySetLength, - 0 -}; +Handle<AccessorInfo> Accessors::ArrayLengthInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->length_string(), + &ArrayLengthGetter, + &ArrayLengthSetter, + attributes); +} + // // Accessors::StringLength // +void Accessors::StringLengthGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* value = *GetThisFrom(info); + Object* result; + if (value->IsJSValue()) value = JSValue::cast(value)->value(); + if (value->IsString()) { + result = Smi::FromInt(String::cast(value)->length()); + } else { + // If object is not a string we return 0 to be compatible with WebKit. + // Note: Firefox returns the length of ToString(object). + result = Smi::FromInt(0); + } + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); +} + -MaybeObject* Accessors::StringGetLength(Isolate* isolate, - Object* object, - void*) { - Object* value = object; - if (object->IsJSValue()) value = JSValue::cast(object)->value(); - if (value->IsString()) return Smi::FromInt(String::cast(value)->length()); - // If object is not a string we return 0 to be compatible with WebKit. - // Note: Firefox returns the length of ToString(object). - return Smi::FromInt(0); +void Accessors::StringLengthSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); } -const AccessorDescriptor Accessors::StringLength = { - StringGetLength, - IllegalSetter, - 0 -}; +Handle<AccessorInfo> Accessors::StringLengthInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->length_string(), + &StringLengthGetter, + &StringLengthSetter, + attributes); +} // -// Accessors::ScriptSource +// Accessors::ScriptColumnOffset // -MaybeObject* Accessors::ScriptGetSource(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->source(); +void Accessors::ScriptColumnOffsetGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* res = Script::cast(JSValue::cast(object)->value())->column_offset(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); } -const AccessorDescriptor Accessors::ScriptSource = { - ScriptGetSource, - IllegalSetter, - 0 -}; - - -// -// Accessors::ScriptName -// - - -MaybeObject* Accessors::ScriptGetName(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->name(); +void Accessors::ScriptColumnOffsetSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); } -const AccessorDescriptor Accessors::ScriptName = { - ScriptGetName, - IllegalSetter, - 0 -}; +Handle<AccessorInfo> Accessors::ScriptColumnOffsetInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("column_offset"))); + return MakeAccessor(isolate, + name, + &ScriptColumnOffsetGetter, + &ScriptColumnOffsetSetter, + attributes); +} // @@ -278,77 +327,143 @@ const AccessorDescriptor Accessors::ScriptName = { // -MaybeObject* Accessors::ScriptGetId(Isolate* isolate, Object* object, void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->id(); +void Accessors::ScriptIdGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* id = Script::cast(JSValue::cast(object)->value())->id(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate))); } -const AccessorDescriptor Accessors::ScriptId = { - ScriptGetId, - IllegalSetter, - 0 -}; +void Accessors::ScriptIdSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptIdInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("id"))); + return MakeAccessor(isolate, + name, + &ScriptIdGetter, + &ScriptIdSetter, + attributes); +} // -// Accessors::ScriptLineOffset +// Accessors::ScriptName // -MaybeObject* Accessors::ScriptGetLineOffset(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->line_offset(); +void Accessors::ScriptNameGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* source = Script::cast(JSValue::cast(object)->value())->name(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate))); } -const AccessorDescriptor Accessors::ScriptLineOffset = { - ScriptGetLineOffset, - IllegalSetter, - 0 -}; +void Accessors::ScriptNameSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptNameInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->name_string(), + &ScriptNameGetter, + &ScriptNameSetter, + attributes); +} // -// Accessors::ScriptColumnOffset +// Accessors::ScriptSource // -MaybeObject* Accessors::ScriptGetColumnOffset(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->column_offset(); +void Accessors::ScriptSourceGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* source = Script::cast(JSValue::cast(object)->value())->source(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate))); } -const AccessorDescriptor Accessors::ScriptColumnOffset = { - ScriptGetColumnOffset, - IllegalSetter, - 0 -}; +void Accessors::ScriptSourceSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptSourceInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->source_string(), + &ScriptSourceGetter, + &ScriptSourceSetter, + attributes); +} // -// Accessors::ScriptData +// Accessors::ScriptLineOffset // -MaybeObject* Accessors::ScriptGetData(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->data(); +void Accessors::ScriptLineOffsetGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* res = Script::cast(JSValue::cast(object)->value())->line_offset(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); } -const AccessorDescriptor Accessors::ScriptData = { - ScriptGetData, - IllegalSetter, - 0 -}; +void Accessors::ScriptLineOffsetSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptLineOffsetInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("line_offset"))); + return MakeAccessor(isolate, + name, + &ScriptLineOffsetGetter, + &ScriptLineOffsetSetter, + attributes); +} // @@ -356,19 +471,36 @@ const AccessorDescriptor Accessors::ScriptData = { // -MaybeObject* Accessors::ScriptGetType(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->type(); +void Accessors::ScriptTypeGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* res = Script::cast(JSValue::cast(object)->value())->type(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); } -const AccessorDescriptor Accessors::ScriptType = { - ScriptGetType, - IllegalSetter, - 0 -}; +void Accessors::ScriptTypeSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptTypeInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("type"))); + return MakeAccessor(isolate, + name, + &ScriptTypeGetter, + &ScriptTypeSetter, + attributes); +} // @@ -376,19 +508,37 @@ const AccessorDescriptor Accessors::ScriptType = { // -MaybeObject* Accessors::ScriptGetCompilationType(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Smi::FromInt(Script::cast(script)->compilation_type()); +void Accessors::ScriptCompilationTypeGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* res = Smi::FromInt( + Script::cast(JSValue::cast(object)->value())->compilation_type()); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); } -const AccessorDescriptor Accessors::ScriptCompilationType = { - ScriptGetCompilationType, - IllegalSetter, - 0 -}; +void Accessors::ScriptCompilationTypeSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptCompilationTypeInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("compilation_type"))); + return MakeAccessor(isolate, + name, + &ScriptCompilationTypeGetter, + &ScriptCompilationTypeSetter, + attributes); +} // @@ -396,13 +546,15 @@ const AccessorDescriptor Accessors::ScriptCompilationType = { // -MaybeObject* Accessors::ScriptGetLineEnds(Isolate* isolate, - Object* object, - void*) { - JSValue* wrapper = JSValue::cast(object); +void Accessors::ScriptLineEndsGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); HandleScope scope(isolate); - Handle<Script> script(Script::cast(wrapper->value()), isolate); - InitScriptLineEnds(script); + Handle<Object> object = Utils::OpenHandle(*info.This()); + Handle<Script> script( + Script::cast(Handle<JSValue>::cast(object)->value()), isolate); + Script::InitLineEnds(script); ASSERT(script->line_ends()->IsFixedArray()); Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); // We do not want anyone to modify this array from JS. @@ -410,15 +562,28 @@ MaybeObject* Accessors::ScriptGetLineEnds(Isolate* isolate, line_ends->map() == isolate->heap()->fixed_cow_array_map()); Handle<JSArray> js_array = isolate->factory()->NewJSArrayWithElements(line_ends); - return *js_array; + info.GetReturnValue().Set(Utils::ToLocal(js_array)); } -const AccessorDescriptor Accessors::ScriptLineEnds = { - ScriptGetLineEnds, - IllegalSetter, - 0 -}; +void Accessors::ScriptLineEndsSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptLineEndsInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("line_ends"))); + return MakeAccessor(isolate, + name, + &ScriptLineEndsGetter, + &ScriptLineEndsSetter, + attributes); +} // @@ -426,19 +591,36 @@ const AccessorDescriptor Accessors::ScriptLineEnds = { // -MaybeObject* Accessors::ScriptGetContextData(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - return Script::cast(script)->context_data(); +void Accessors::ScriptContextDataGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* object = *Utils::OpenHandle(*info.This()); + Object* res = Script::cast(JSValue::cast(object)->value())->context_data(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); } -const AccessorDescriptor Accessors::ScriptContextData = { - ScriptGetContextData, - IllegalSetter, - 0 -}; +void Accessors::ScriptContextDataSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptContextDataInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("context_data"))); + return MakeAccessor(isolate, + name, + &ScriptContextDataGetter, + &ScriptContextDataSetter, + attributes); +} // @@ -446,28 +628,46 @@ const AccessorDescriptor Accessors::ScriptContextData = { // -MaybeObject* Accessors::ScriptGetEvalFromScript(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - if (!Script::cast(script)->eval_from_shared()->IsUndefined()) { +void Accessors::ScriptEvalFromScriptGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = Utils::OpenHandle(*info.This()); + Handle<Script> script( + Script::cast(Handle<JSValue>::cast(object)->value()), isolate); + Handle<Object> result = isolate->factory()->undefined_value(); + if (!script->eval_from_shared()->IsUndefined()) { Handle<SharedFunctionInfo> eval_from_shared( - SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared())); - + SharedFunctionInfo::cast(script->eval_from_shared())); if (eval_from_shared->script()->IsScript()) { Handle<Script> eval_from_script(Script::cast(eval_from_shared->script())); - return *GetScriptWrapper(eval_from_script); + result = Script::GetWrapper(eval_from_script); } } - return isolate->heap()->undefined_value(); + + info.GetReturnValue().Set(Utils::ToLocal(result)); } -const AccessorDescriptor Accessors::ScriptEvalFromScript = { - ScriptGetEvalFromScript, - IllegalSetter, - 0 -}; +void Accessors::ScriptEvalFromScriptSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptEvalFromScriptInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("eval_from_script"))); + return MakeAccessor(isolate, + name, + &ScriptEvalFromScriptGetter, + &ScriptEvalFromScriptSetter, + attributes); +} // @@ -475,32 +675,45 @@ const AccessorDescriptor Accessors::ScriptEvalFromScript = { // -MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Isolate* isolate, - Object* object, - void*) { - Script* raw_script = Script::cast(JSValue::cast(object)->value()); +void Accessors::ScriptEvalFromScriptPositionGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); HandleScope scope(isolate); - Handle<Script> script(raw_script); - - // If this is not a script compiled through eval there is no eval position. - if (script->compilation_type() != Script::COMPILATION_TYPE_EVAL) { - return script->GetHeap()->undefined_value(); + Handle<Object> object = Utils::OpenHandle(*info.This()); + Handle<Script> script( + Script::cast(Handle<JSValue>::cast(object)->value()), isolate); + Handle<Object> result = isolate->factory()->undefined_value(); + if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) { + Handle<Code> code(SharedFunctionInfo::cast( + script->eval_from_shared())->code()); + result = Handle<Object>( + Smi::FromInt(code->SourcePosition(code->instruction_start() + + script->eval_from_instructions_offset()->value())), + isolate); } + info.GetReturnValue().Set(Utils::ToLocal(result)); +} + - // Get the function from where eval was called and find the source position - // from the instruction offset. - Handle<Code> code(SharedFunctionInfo::cast( - script->eval_from_shared())->code()); - return Smi::FromInt(code->SourcePosition(code->instruction_start() + - script->eval_from_instructions_offset()->value())); +void Accessors::ScriptEvalFromScriptPositionSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); } -const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { - ScriptGetEvalFromScriptPosition, - IllegalSetter, - 0 -}; +Handle<AccessorInfo> Accessors::ScriptEvalFromScriptPositionInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("eval_from_script_position"))); + return MakeAccessor(isolate, + name, + &ScriptEvalFromScriptPositionGetter, + &ScriptEvalFromScriptPositionSetter, + attributes); +} // @@ -508,103 +721,96 @@ const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { // -MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Isolate* isolate, - Object* object, - void*) { - Object* script = JSValue::cast(object)->value(); - Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast( - Script::cast(script)->eval_from_shared())); - - +void Accessors::ScriptEvalFromFunctionNameGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = Utils::OpenHandle(*info.This()); + Handle<Script> script( + Script::cast(Handle<JSValue>::cast(object)->value()), isolate); + Handle<Object> result; + Handle<SharedFunctionInfo> shared( + SharedFunctionInfo::cast(script->eval_from_shared())); // Find the name of the function calling eval. if (!shared->name()->IsUndefined()) { - return shared->name(); + result = Handle<Object>(shared->name(), isolate); } else { - return shared->inferred_name(); + result = Handle<Object>(shared->inferred_name(), isolate); } + info.GetReturnValue().Set(Utils::ToLocal(result)); } -const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { - ScriptGetEvalFromFunctionName, - IllegalSetter, - 0 -}; +void Accessors::ScriptEvalFromFunctionNameSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + UNREACHABLE(); +} + + +Handle<AccessorInfo> Accessors::ScriptEvalFromFunctionNameInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<String> name(isolate->factory()->InternalizeOneByteString( + STATIC_ASCII_VECTOR("eval_from_function_name"))); + return MakeAccessor(isolate, + name, + &ScriptEvalFromFunctionNameGetter, + &ScriptEvalFromFunctionNameSetter, + attributes); +} // // Accessors::FunctionPrototype // +static Handle<Object> GetFunctionPrototype(Isolate* isolate, + Handle<Object> receiver) { + Handle<JSFunction> function; + { + DisallowHeapAllocation no_allocation; + JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, *receiver); + if (function_raw == NULL) return isolate->factory()->undefined_value(); + while (!function_raw->should_have_prototype()) { + function_raw = FindInstanceOf<JSFunction>(isolate, + function_raw->GetPrototype()); + // There has to be one because we hit the getter. + ASSERT(function_raw != NULL); + } + function = Handle<JSFunction>(function_raw, isolate); + } -Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) { - CALL_HEAP_FUNCTION(function->GetIsolate(), - Accessors::FunctionGetPrototype(function->GetIsolate(), - *function, - NULL), - Object); -} - - -Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function, - Handle<Object> prototype) { - ASSERT(function->should_have_prototype()); - CALL_HEAP_FUNCTION(function->GetIsolate(), - Accessors::FunctionSetPrototype(function->GetIsolate(), - *function, - *prototype, - NULL), - Object); -} - - -MaybeObject* Accessors::FunctionGetPrototype(Isolate* isolate, - Object* object, - void*) { - JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object); - if (function_raw == NULL) return isolate->heap()->undefined_value(); - while (!function_raw->should_have_prototype()) { - function_raw = FindInstanceOf<JSFunction>(isolate, - function_raw->GetPrototype()); - // There has to be one because we hit the getter. - ASSERT(function_raw != NULL); - } - - if (!function_raw->has_prototype()) { - HandleScope scope(isolate); - Handle<JSFunction> function(function_raw); + if (!function->has_prototype()) { Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function); JSFunction::SetPrototype(function, proto); - function_raw = *function; } - return function_raw->prototype(); + return Handle<Object>(function->prototype(), isolate); } -MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate, - JSObject* object_raw, - Object* value_raw, - void*) { - JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object_raw); - if (function_raw == NULL) return isolate->heap()->undefined_value(); +static Handle<Object> SetFunctionPrototype(Isolate* isolate, + Handle<JSObject> receiver, + Handle<Object> value) { + Handle<JSFunction> function; + { + DisallowHeapAllocation no_allocation; + JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, *receiver); + if (function_raw == NULL) return isolate->factory()->undefined_value(); + function = Handle<JSFunction>(function_raw, isolate); + } - HandleScope scope(isolate); - Handle<JSFunction> function(function_raw, isolate); - Handle<JSObject> object(object_raw, isolate); - Handle<Object> value(value_raw, isolate); if (!function->should_have_prototype()) { // Since we hit this accessor, object will have no prototype property. - Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object, - isolate->factory()->prototype_string(), value, NONE); - RETURN_IF_EMPTY_HANDLE(isolate, result); - return *result; + MaybeHandle<Object> maybe_result = + JSObject::SetOwnPropertyIgnoreAttributes( + receiver, isolate->factory()->prototype_string(), value, NONE); + return maybe_result.ToHandleChecked(); } Handle<Object> old_value; - bool is_observed = - FLAG_harmony_observation && - *function == *object && - function->map()->is_observed(); + bool is_observed = *function == *receiver && function->map()->is_observed(); if (is_observed) { if (function->has_prototype()) old_value = handle(function->prototype(), isolate); @@ -620,15 +826,56 @@ MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate, function, "update", isolate->factory()->prototype_string(), old_value); } - return *function; + return function; } -const AccessorDescriptor Accessors::FunctionPrototype = { - FunctionGetPrototype, - FunctionSetPrototype, - 0 -}; +Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) { + return GetFunctionPrototype(function->GetIsolate(), function); +} + + +Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function, + Handle<Object> prototype) { + ASSERT(function->should_have_prototype()); + Isolate* isolate = function->GetIsolate(); + return SetFunctionPrototype(isolate, function, prototype); +} + + +void Accessors::FunctionPrototypeGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = GetThisFrom(info); + Handle<Object> result = GetFunctionPrototype(isolate, object); + info.GetReturnValue().Set(Utils::ToLocal(result)); +} + + +void Accessors::FunctionPrototypeSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<JSObject> object = + Handle<JSObject>::cast(Utils::OpenHandle(*info.This())); + Handle<Object> value = Utils::OpenHandle(*val); + + SetFunctionPrototype(isolate, object, value); +} + + +Handle<AccessorInfo> Accessors::FunctionPrototypeInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->prototype_string(), + &FunctionPrototypeGetter, + &FunctionPrototypeSetter, + attributes); +} // @@ -636,31 +883,57 @@ const AccessorDescriptor Accessors::FunctionPrototype = { // -MaybeObject* Accessors::FunctionGetLength(Isolate* isolate, - Object* object, - void*) { - JSFunction* function = FindInstanceOf<JSFunction>(isolate, object); - if (function == NULL) return Smi::FromInt(0); - // Check if already compiled. - 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. +void Accessors::FunctionLengthGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); HandleScope scope(isolate); - Handle<JSFunction> handle(function); - if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { - return Smi::FromInt(handle->shared()->length()); + Handle<Object> object = GetThisFrom(info); + MaybeHandle<JSFunction> maybe_function; + + { + DisallowHeapAllocation no_allocation; + JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object); + if (function != NULL) maybe_function = Handle<JSFunction>(function); + } + + int length = 0; + Handle<JSFunction> function; + if (maybe_function.ToHandle(&function)) { + if (function->shared()->is_compiled()) { + length = function->shared()->length(); + } else { + // If the function isn't compiled yet, the length is not computed + // correctly yet. Compile it now and return the right length. + if (Compiler::EnsureCompiled(function, KEEP_EXCEPTION)) { + length = function->shared()->length(); + } + if (isolate->has_pending_exception()) { + isolate->OptionalRescheduleException(false); + } + } } - return Failure::Exception(); + Handle<Object> result(Smi::FromInt(length), isolate); + info.GetReturnValue().Set(Utils::ToLocal(result)); } -const AccessorDescriptor Accessors::FunctionLength = { - FunctionGetLength, - ReadOnlySetAccessor, - 0 -}; +void Accessors::FunctionLengthSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + // Do nothing. +} + + +Handle<AccessorInfo> Accessors::FunctionLengthInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->length_string(), + &FunctionLengthGetter, + &FunctionLengthSetter, + attributes); +} // @@ -668,21 +941,47 @@ const AccessorDescriptor Accessors::FunctionLength = { // -MaybeObject* Accessors::FunctionGetName(Isolate* isolate, - Object* object, - void*) { - JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); - return holder == NULL - ? isolate->heap()->undefined_value() - : holder->shared()->name(); +void Accessors::FunctionNameGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = GetThisFrom(info); + MaybeHandle<JSFunction> maybe_function; + + { + DisallowHeapAllocation no_allocation; + JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object); + if (function != NULL) maybe_function = Handle<JSFunction>(function); + } + + Handle<JSFunction> function; + Handle<Object> result; + if (maybe_function.ToHandle(&function)) { + result = Handle<Object>(function->shared()->name(), isolate); + } else { + result = isolate->factory()->undefined_value(); + } + info.GetReturnValue().Set(Utils::ToLocal(result)); +} + + +void Accessors::FunctionNameSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + // Do nothing. } -const AccessorDescriptor Accessors::FunctionName = { - FunctionGetName, - ReadOnlySetAccessor, - 0 -}; +Handle<AccessorInfo> Accessors::FunctionNameInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->name_string(), + &FunctionNameGetter, + &FunctionNameSetter, + attributes); +} // @@ -690,113 +989,148 @@ const AccessorDescriptor Accessors::FunctionName = { // -Handle<Object> Accessors::FunctionGetArguments(Handle<JSFunction> function) { - CALL_HEAP_FUNCTION(function->GetIsolate(), - Accessors::FunctionGetArguments(function->GetIsolate(), - *function, - NULL), - Object); -} - - -static MaybeObject* ConstructArgumentsObjectForInlinedFunction( +static Handle<Object> ArgumentsForInlinedFunction( JavaScriptFrame* frame, Handle<JSFunction> inlined_function, int inlined_frame_index) { Isolate* isolate = inlined_function->GetIsolate(); Factory* factory = isolate->factory(); - Vector<SlotRef> args_slots = - SlotRef::ComputeSlotMappingForArguments( - frame, - inlined_frame_index, - inlined_function->shared()->formal_parameter_count()); - int args_count = args_slots.length(); + SlotRefValueBuilder slot_refs( + frame, + inlined_frame_index, + inlined_function->shared()->formal_parameter_count()); + + int args_count = slot_refs.args_length(); Handle<JSObject> arguments = factory->NewArgumentsObject(inlined_function, args_count); Handle<FixedArray> array = factory->NewFixedArray(args_count); + slot_refs.Prepare(isolate); for (int i = 0; i < args_count; ++i) { - Handle<Object> value = args_slots[i].GetValue(isolate); + Handle<Object> value = slot_refs.GetNext(isolate, 0); array->set(i, *value); } + slot_refs.Finish(isolate); arguments->set_elements(*array); - args_slots.Dispose(); // Return the freshly allocated arguments object. - return *arguments; + return arguments; } -MaybeObject* Accessors::FunctionGetArguments(Isolate* isolate, - Object* object, - void*) { - HandleScope scope(isolate); - JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); - if (holder == NULL) return isolate->heap()->undefined_value(); - Handle<JSFunction> function(holder, isolate); +static int FindFunctionInFrame(JavaScriptFrame* frame, + Handle<JSFunction> function) { + DisallowHeapAllocation no_allocation; + List<JSFunction*> functions(2); + frame->GetFunctions(&functions); + for (int i = functions.length() - 1; i >= 0; i--) { + if (functions[i] == *function) return i; + } + return -1; +} + + +Handle<Object> GetFunctionArguments(Isolate* isolate, + Handle<JSFunction> function) { + if (function->shared()->native()) return isolate->factory()->null_value(); - if (function->shared()->native()) return isolate->heap()->null_value(); // Find the top invocation of the function by traversing frames. - List<JSFunction*> functions(2); for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { JavaScriptFrame* frame = it.frame(); - frame->GetFunctions(&functions); - for (int i = functions.length() - 1; i >= 0; i--) { - // Skip all frames that aren't invocations of the given function. - if (functions[i] != *function) continue; - - if (i > 0) { - // The function in question was inlined. Inlined functions have the - // correct number of arguments and no allocated arguments object, so - // we can construct a fresh one by interpreting the function's - // deoptimization input data. - return ConstructArgumentsObjectForInlinedFunction(frame, function, i); - } + int function_index = FindFunctionInFrame(frame, function); + if (function_index < 0) continue; + + if (function_index > 0) { + // The function in question was inlined. Inlined functions have the + // correct number of arguments and no allocated arguments object, so + // we can construct a fresh one by interpreting the function's + // deoptimization input data. + return ArgumentsForInlinedFunction(frame, function, function_index); + } - if (!frame->is_optimized()) { - // If there is an arguments variable in the stack, we return that. - Handle<ScopeInfo> scope_info(function->shared()->scope_info()); - int index = scope_info->StackSlotIndex( - isolate->heap()->arguments_string()); - if (index >= 0) { - Handle<Object> arguments(frame->GetExpression(index), isolate); - if (!arguments->IsArgumentsMarker()) return *arguments; - } + if (!frame->is_optimized()) { + // If there is an arguments variable in the stack, we return that. + Handle<ScopeInfo> scope_info(function->shared()->scope_info()); + int index = scope_info->StackSlotIndex( + isolate->heap()->arguments_string()); + if (index >= 0) { + Handle<Object> arguments(frame->GetExpression(index), isolate); + if (!arguments->IsArgumentsMarker()) return arguments; } - - // If there is no arguments variable in the stack or we have an - // optimized frame, we find the frame that holds the actual arguments - // passed to the function. - it.AdvanceToArgumentsFrame(); - frame = it.frame(); - - // Get the number of arguments and construct an arguments object - // mirror for the right frame. - const int length = frame->ComputeParametersCount(); - Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject( - function, length); - Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); - - // Copy the parameters to the arguments object. - ASSERT(array->length() == length); - for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); - arguments->set_elements(*array); - - // Return the freshly allocated arguments object. - return *arguments; } - functions.Rewind(0); + + // If there is no arguments variable in the stack or we have an + // optimized frame, we find the frame that holds the actual arguments + // passed to the function. + it.AdvanceToArgumentsFrame(); + frame = it.frame(); + + // Get the number of arguments and construct an arguments object + // mirror for the right frame. + const int length = frame->ComputeParametersCount(); + Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject( + function, length); + Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); + + // Copy the parameters to the arguments object. + ASSERT(array->length() == length); + for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); + arguments->set_elements(*array); + + // Return the freshly allocated arguments object. + return arguments; } // No frame corresponding to the given function found. Return null. - return isolate->heap()->null_value(); + return isolate->factory()->null_value(); } -const AccessorDescriptor Accessors::FunctionArguments = { - FunctionGetArguments, - ReadOnlySetAccessor, - 0 -}; +Handle<Object> Accessors::FunctionGetArguments(Handle<JSFunction> function) { + return GetFunctionArguments(function->GetIsolate(), function); +} + + +void Accessors::FunctionArgumentsGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = GetThisFrom(info); + MaybeHandle<JSFunction> maybe_function; + + { + DisallowHeapAllocation no_allocation; + JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object); + if (function != NULL) maybe_function = Handle<JSFunction>(function); + } + + Handle<JSFunction> function; + Handle<Object> result; + if (maybe_function.ToHandle(&function)) { + result = GetFunctionArguments(isolate, function); + } else { + result = isolate->factory()->undefined_value(); + } + info.GetReturnValue().Set(Utils::ToLocal(result)); +} + + +void Accessors::FunctionArgumentsSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + // Do nothing. +} + + +Handle<AccessorInfo> Accessors::FunctionArgumentsInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->arguments_string(), + &FunctionArgumentsGetter, + &FunctionArgumentsSetter, + attributes); +} // @@ -804,22 +1138,33 @@ const AccessorDescriptor Accessors::FunctionArguments = { // +static inline bool AllowAccessToFunction(Context* current_context, + JSFunction* function) { + return current_context->HasSameSecurityTokenAs(function->context()); +} + + class FrameFunctionIterator { public: FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise) - : frame_iterator_(isolate), + : isolate_(isolate), + frame_iterator_(isolate), functions_(2), index_(0) { GetFunctions(); } JSFunction* next() { - if (functions_.length() == 0) return NULL; - JSFunction* next_function = functions_[index_]; - index_--; - if (index_ < 0) { - GetFunctions(); + while (true) { + if (functions_.length() == 0) return NULL; + JSFunction* next_function = functions_[index_]; + index_--; + if (index_ < 0) { + GetFunctions(); + } + // Skip functions from other origins. + if (!AllowAccessToFunction(isolate_->context(), next_function)) continue; + return next_function; } - return next_function; } // Iterate through functions until the first occurence of 'function'. @@ -844,35 +1189,30 @@ class FrameFunctionIterator { frame_iterator_.Advance(); index_ = functions_.length() - 1; } + Isolate* isolate_; JavaScriptFrameIterator frame_iterator_; List<JSFunction*> functions_; int index_; }; -MaybeObject* Accessors::FunctionGetCaller(Isolate* isolate, - Object* object, - void*) { - HandleScope scope(isolate); +MaybeHandle<JSFunction> FindCaller(Isolate* isolate, + Handle<JSFunction> function) { DisallowHeapAllocation no_allocation; - JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); - if (holder == NULL) return isolate->heap()->undefined_value(); - if (holder->shared()->native()) return isolate->heap()->null_value(); - Handle<JSFunction> function(holder, isolate); - FrameFunctionIterator it(isolate, no_allocation); - + if (function->shared()->native()) { + return MaybeHandle<JSFunction>(); + } // Find the function from the frames. if (!it.Find(*function)) { // No frame corresponding to the given function found. Return null. - return isolate->heap()->null_value(); + return MaybeHandle<JSFunction>(); } - // Find previously called non-toplevel function. JSFunction* caller; do { caller = it.next(); - if (caller == NULL) return isolate->heap()->null_value(); + if (caller == NULL) return MaybeHandle<JSFunction>(); } while (caller->shared()->is_toplevel()); // If caller is a built-in function and caller's caller is also built-in, @@ -889,24 +1229,68 @@ MaybeObject* Accessors::FunctionGetCaller(Isolate* isolate, // allows us to make bound functions use the strict function map // and its associated throwing caller and arguments. if (caller->shared()->bound()) { - return isolate->heap()->null_value(); + return MaybeHandle<JSFunction>(); } - // Censor if the caller is not a classic mode function. + // Censor if the caller is not a sloppy mode function. // Change from ES5, which used to throw, see: // https://bugs.ecmascript.org/show_bug.cgi?id=310 - if (!caller->shared()->is_classic_mode()) { - return isolate->heap()->null_value(); + if (caller->shared()->strict_mode() == STRICT) { + return MaybeHandle<JSFunction>(); + } + // Don't return caller from another security context. + if (!AllowAccessToFunction(isolate->context(), caller)) { + return MaybeHandle<JSFunction>(); + } + return Handle<JSFunction>(caller); +} + + +void Accessors::FunctionCallerGetter( + v8::Local<v8::String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<Object> object = GetThisFrom(info); + MaybeHandle<JSFunction> maybe_function; + { + DisallowHeapAllocation no_allocation; + JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object); + if (function != NULL) maybe_function = Handle<JSFunction>(function); + } + Handle<JSFunction> function; + Handle<Object> result; + if (maybe_function.ToHandle(&function)) { + MaybeHandle<JSFunction> maybe_caller; + maybe_caller = FindCaller(isolate, function); + Handle<JSFunction> caller; + if (maybe_caller.ToHandle(&caller)) { + result = caller; + } else { + result = isolate->factory()->null_value(); + } + } else { + result = isolate->factory()->undefined_value(); } + info.GetReturnValue().Set(Utils::ToLocal(result)); +} + - return caller; +void Accessors::FunctionCallerSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + // Do nothing. } -const AccessorDescriptor Accessors::FunctionCaller = { - FunctionGetCaller, - ReadOnlySetAccessor, - 0 -}; +Handle<AccessorInfo> Accessors::FunctionCallerInfo( + Isolate* isolate, PropertyAttributes attributes) { + return MakeAccessor(isolate, + isolate->factory()->caller_string(), + &FunctionCallerGetter, + &FunctionCallerSetter, + attributes); +} // |