📄 objects.cc.svn-base
字号:
// Copyright 2006-2008 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 "api.h"#include "bootstrapper.h"#include "debug.h"#include "execution.h"#include "objects-inl.h"#include "macro-assembler.h"#include "scanner.h"#include "scopeinfo.h"#include "string-stream.h"#ifdef ENABLE_DISASSEMBLER#include "disassembler.h"#endifnamespace v8 { namespace internal {// Getters and setters are stored in a fixed array property. These are// constants for their indices.const int kGetterIndex = 0;const int kSetterIndex = 1;bool Object::IsInstanceOf(FunctionTemplateInfo* expected) { // There is a constraint on the object; check if (!this->IsJSObject()) return false; // Fetch the constructor function of the object Object* cons_obj = JSObject::cast(this)->map()->constructor(); if (!cons_obj->IsJSFunction()) return false; JSFunction* fun = JSFunction::cast(cons_obj); // Iterate through the chain of inheriting function templates to // see if the required one occurs. for (Object* type = fun->shared()->function_data(); type->IsFunctionTemplateInfo(); type = FunctionTemplateInfo::cast(type)->parent_template()) { if (type == expected) return true; } // Didn't find the required type in the inheritance chain. return false;}static Object* CreateJSValue(JSFunction* constructor, Object* value) { Object* result = Heap::AllocateJSObject(constructor); if (result->IsFailure()) return result; JSValue::cast(result)->set_value(value); return result;}Object* Object::ToObject(Context* global_context) { if (IsNumber()) { return CreateJSValue(global_context->number_function(), this); } else if (IsBoolean()) { return CreateJSValue(global_context->boolean_function(), this); } else if (IsString()) { return CreateJSValue(global_context->string_function(), this); } ASSERT(IsJSObject()); return this;}Object* Object::ToObject() { Context* global_context = Top::context()->global_context(); if (IsJSObject()) { return this; } else if (IsNumber()) { return CreateJSValue(global_context->number_function(), this); } else if (IsBoolean()) { return CreateJSValue(global_context->boolean_function(), this); } else if (IsString()) { return CreateJSValue(global_context->string_function(), this); } // Throw a type error. return Failure::InternalError();}Object* Object::ToBoolean() { if (IsTrue()) return Heap::true_value(); if (IsFalse()) return Heap::false_value(); if (IsSmi()) { return Heap::ToBoolean(Smi::cast(this)->value() != 0); } if (IsUndefined() || IsNull()) return Heap::false_value(); // Undetectable object is false if (IsUndetectableObject()) { return Heap::false_value(); } if (IsString()) { return Heap::ToBoolean(String::cast(this)->length() != 0); } if (IsHeapNumber()) { return HeapNumber::cast(this)->HeapNumberToBoolean(); } return Heap::true_value();}void Object::Lookup(String* name, LookupResult* result) { if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result); Object* holder = NULL; Context* global_context = Top::context()->global_context(); if (IsString()) { holder = global_context->string_function()->instance_prototype(); } else if (IsNumber()) { holder = global_context->number_function()->instance_prototype(); } else if (IsBoolean()) { holder = global_context->boolean_function()->instance_prototype(); }#ifdef DEBUG // Used to track outstanding bug #1308895. // TODO(1308895) Remove when bug is fixed. if (holder == NULL) { PrintF("\nName being looked up: "); name->Print(); PrintF("\nThis (object name is looked up in: "); this->Print(); if (IsScript()) { PrintF("IsScript() returns true.\n"); } }#endif ASSERT(holder != NULL); // cannot handle null or undefined. JSObject::cast(holder)->Lookup(name, result);}Object* Object::GetPropertyWithReceiver(Object* receiver, String* name, PropertyAttributes* attributes) { LookupResult result; Lookup(name, &result); return GetProperty(receiver, &result, name, attributes);}Object* Object::GetPropertyWithCallback(Object* receiver, Object* structure, String* name, Object* holder) { // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually proxy // callbacks should be phased out. if (structure->IsProxy()) { AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); Object* value = (callback->getter)(receiver, callback->data); RETURN_IF_SCHEDULED_EXCEPTION(); return value; } // api style callbacks. if (structure->IsAccessorInfo()) { AccessorInfo* data = AccessorInfo::cast(structure); Object* fun_obj = data->getter(); v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); HandleScope scope; Handle<JSObject> self(JSObject::cast(receiver)); Handle<JSObject> holder_handle(JSObject::cast(holder)); Handle<String> key(name); Handle<Object> fun_data(data->data()); LOG(ApiNamedPropertyAccess("load", *self, name)); v8::AccessorInfo info(v8::Utils::ToLocal(self), v8::Utils::ToLocal(fun_data), v8::Utils::ToLocal(holder_handle)); v8::Handle<v8::Value> result; { // Leaving JavaScript. VMState state(OTHER); result = call_fun(v8::Utils::ToLocal(key), info); } RETURN_IF_SCHEDULED_EXCEPTION(); if (result.IsEmpty()) return Heap::undefined_value(); return *v8::Utils::OpenHandle(*result); } // __defineGetter__ callback if (structure->IsFixedArray()) { Object* getter = FixedArray::cast(structure)->get(kGetterIndex); if (getter->IsJSFunction()) { HandleScope scope; Handle<JSFunction> fun(JSFunction::cast(getter)); Handle<Object> self(receiver); bool has_pending_exception; Object* result = *Execution::Call(fun, self, 0, NULL, &has_pending_exception); // Check for pending exception and return the result. if (has_pending_exception) return Failure::Exception(); return result; } // Getter is not a function. return Heap::undefined_value(); } UNREACHABLE(); return 0;}// Only deal with CALLBACKS and INTERCEPTORObject* JSObject::GetPropertyWithFailedAccessCheck(Object* receiver, LookupResult* result, String* name) { if (result->IsValid()) { switch (result->type()) { case CALLBACKS: { // Only allow API accessors. Object* obj = result->GetCallbackObject(); if (obj->IsAccessorInfo()) { AccessorInfo* info = AccessorInfo::cast(obj); if (info->all_can_read()) { return GetPropertyWithCallback(receiver, result->GetCallbackObject(), name, result->holder()); } } break; } case NORMAL: case FIELD: case CONSTANT_FUNCTION: { // Search ALL_CAN_READ accessors in prototype chain. LookupResult r; result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); if (r.IsValid()) { return GetPropertyWithFailedAccessCheck(receiver, &r, name); } break; } case INTERCEPTOR: { // If the object has an interceptor, try real named properties. // No access check in GetPropertyAttributeWithInterceptor. LookupResult r; result->holder()->LookupRealNamedProperty(name, &r); if (r.IsValid()) { return GetPropertyWithFailedAccessCheck(receiver, &r, name); } break; } default: { break; } } } Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); return Heap::undefined_value();}Object* JSObject::GetLazyProperty(Object* receiver, LookupResult* result, String* name, PropertyAttributes* attributes) { HandleScope scope; Handle<Object> this_handle(this); Handle<Object> receiver_handle(receiver); Handle<String> name_handle(name); bool pending_exception; LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->GetPropertyWithReceiver(*receiver_handle, *name_handle, attributes);}Object* JSObject::SetLazyProperty(LookupResult* result, String* name, Object* value, PropertyAttributes attributes) { HandleScope scope; Handle<JSObject> this_handle(this); Handle<String> name_handle(name); Handle<Object> value_handle(value); bool pending_exception; LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->SetProperty(*name_handle, *value_handle, attributes);}Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) { HandleScope scope; Handle<JSObject> this_handle(this); Handle<String> name_handle(name); bool pending_exception; LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->DeleteProperty(*name_handle);}Object* Object::GetProperty(Object* receiver, LookupResult* result, String* name, PropertyAttributes* attributes) { // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; // Traverse the prototype chain from the current object (this) to // the holder and check for access rights. This avoid traversing the // objects more than once in case of interceptors, because the // holder will always be the interceptor holder and the search may // only continue with a current object just after the interceptor // holder in the prototype chain. Object* last = result->IsValid() ? result->holder() : Heap::null_value(); for (Object* current = this; true; current = current->GetPrototype()) { if (current->IsAccessCheckNeeded()) { // Check if we're allowed to read from the current object. Note // that even though we may not actually end up loading the named // property from the current object, we still check that we have // access to the it. JSObject* checked = JSObject::cast(current); if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) { return checked->GetPropertyWithFailedAccessCheck(receiver, result, name); } } // Stop traversing the chain once we reach the last object in the // chain; either the holder of the result or null in case of an // absent property. if (current == last) break; } if (!result->IsProperty()) { *attributes = ABSENT; return Heap::undefined_value(); } *attributes = result->GetAttributes(); if (!result->IsLoaded()) { return JSObject::cast(this)->GetLazyProperty(receiver, result, name, attributes); } Object* value; JSObject* holder = result->holder(); switch (result->type()) { case NORMAL: value = holder->property_dictionary()->ValueAt(result->GetDictionaryEntry()); ASSERT(!value->IsTheHole() || result->IsReadOnly()); return value->IsTheHole() ? Heap::undefined_value() : value; case FIELD: value = holder->properties()->get(result->GetFieldIndex());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -