📄 runtime.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 <stdlib.h>#include "v8.h"#include "accessors.h"#include "api.h"#include "arguments.h"#include "compiler.h"#include "cpu.h"#include "dateparser.h"#include "debug.h"#include "execution.h"#include "jsregexp.h"#include "platform.h"#include "runtime.h"#include "scopeinfo.h"#include "v8threads.h"namespace v8 { namespace internal {#define RUNTIME_ASSERT(value) do { \ if (!(value)) return IllegalOperation(); \} while (false)// Cast the given object to a value of the specified type and store// it in a variable with the given name. If the object is not of the// expected type call IllegalOperation and return.#define CONVERT_CHECKED(Type, name, obj) \ RUNTIME_ASSERT(obj->Is##Type()); \ Type* name = Type::cast(obj);#define CONVERT_ARG_CHECKED(Type, name, index) \ RUNTIME_ASSERT(args[index]->Is##Type()); \ Handle<Type> name = args.at<Type>(index);// Cast the given object to a boolean and store it in a variable with// the given name. If the object is not a boolean call IllegalOperation// and return.#define CONVERT_BOOLEAN_CHECKED(name, obj) \ RUNTIME_ASSERT(obj->IsBoolean()); \ bool name = (obj)->IsTrue();// Cast the given object to a double and store it in a variable with// the given name. If the object is not a number (as opposed to// the number not-a-number) call IllegalOperation and return.#define CONVERT_DOUBLE_CHECKED(name, obj) \ RUNTIME_ASSERT(obj->IsNumber()); \ double name = (obj)->Number();// Call the specified converter on the object *comand store the result in// a variable of the specified type with the given name. If the// object is not a Number call IllegalOperation and return.#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ RUNTIME_ASSERT(obj->IsNumber()); \ type name = NumberTo##Type(obj);// Non-reentrant string buffer for efficient general use in this file.static StaticResource<StringInputBuffer> string_input_buffer;static Object* IllegalOperation() { return Top::Throw(Heap::illegal_access_symbol());}static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) { CONVERT_CHECKED(JSObject, boilerplate, args[0]); return boilerplate->Copy();}static Handle<Map> ComputeObjectLiteralMap( Handle<Context> context, Handle<FixedArray> constant_properties, bool &is_result_from_cache) { if (FLAG_canonicalize_object_literal_maps) { // First find prefix of consecutive symbol keys. int number_of_properties = constant_properties->length()/2; int number_of_symbol_keys = 0; while ((number_of_symbol_keys < number_of_properties) && (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) { number_of_symbol_keys++; } // Based on the number of prefix symbols key we decide whether // to use the map cache in the global context. const int kMaxKeys = 10; if ((number_of_symbol_keys == number_of_properties) && (number_of_symbol_keys < kMaxKeys)) { // Create the fixed array with the key. Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys); for (int i = 0; i < number_of_symbol_keys; i++) { keys->set(i, constant_properties->get(i*2)); } is_result_from_cache = true; return Factory::ObjectLiteralMapFromCache(context, keys); } } is_result_from_cache = false; return Handle<Map>(context->object_function()->initial_map());}static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { HandleScope scope; ASSERT(args.length() == 3); // Copy the arguments. Handle<FixedArray> literals = args.at<FixedArray>(0); int literals_index = Smi::cast(args[1])->value(); Handle<FixedArray> constant_properties = args.at<FixedArray>(2); Handle<Context> context = Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); bool is_result_from_cache; Handle<Map> map = ComputeObjectLiteralMap(context, constant_properties, is_result_from_cache); // Get the object function from the literals array. This is the // object function from the context in which the function was // created. We do not use the object function from the current // global context because this might be the object function from // another context which we should not have access to. Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); { // Add the constant propeties to the boilerplate. int length = constant_properties->length(); OptimizedObjectForAddingMultipleProperties opt(boilerplate, !is_result_from_cache); for (int index = 0; index < length; index +=2) { Handle<Object> key(constant_properties->get(index+0)); Handle<Object> value(constant_properties->get(index+1)); uint32_t element_index = 0; if (key->IsSymbol()) { // If key is a symbol it is not an array element. Handle<String> name(String::cast(*key)); ASSERT(!name->AsArrayIndex(&element_index)); SetProperty(boilerplate, name, value, NONE); } else if (Array::IndexFromObject(*key, &element_index)) { // Array index (uint32). SetElement(boilerplate, element_index, value); } else { // Non-uint32 number. ASSERT(key->IsNumber()); double num = key->Number(); char arr[100]; Vector<char> buffer(arr, ARRAY_SIZE(arr)); const char* str = DoubleToCString(num, buffer); Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); SetProperty(boilerplate, name, value, NONE); } } } // Update the functions literal and return the boilerplate. literals->set(literals_index, *boilerplate); return *boilerplate;}static Object* Runtime_CreateArrayLiteral(Arguments args) { // Takes a FixedArray of elements containing the literal elements of // the array literal and produces JSArray with those elements. // Additionally takes the literals array of the surrounding function // which contains the Array function to use for creating the array // literal. ASSERT(args.length() == 2); CONVERT_CHECKED(FixedArray, elements, args[0]); CONVERT_CHECKED(FixedArray, literals, args[1]); JSFunction* constructor = JSFunction::GlobalContextFromLiterals(literals)->array_function(); // Create the JSArray. Object* object = Heap::AllocateJSObject(constructor); if (object->IsFailure()) return object; // Copy the elements. Object* content = elements->Copy(); if (content->IsFailure()) return content; // Set the elements. JSArray::cast(object)->SetContent(FixedArray::cast(content)); return object;}static Object* Runtime_ClassOf(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 1); Object* obj = args[0]; if (!obj->IsJSObject()) return Heap::null_value(); return JSObject::cast(obj)->class_name();}static Object* Runtime_IsInPrototypeChain(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 2); // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). Object* O = args[0]; Object* V = args[1]; while (true) { Object* prototype = V->GetPrototype(); if (prototype->IsNull()) return Heap::false_value(); if (O == prototype) return Heap::true_value(); V = prototype; }}static Object* Runtime_IsConstructCall(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 0); JavaScriptFrameIterator it; return Heap::ToBoolean(it.frame()->IsConstructor());}static Object* Runtime_RegExpCompile(Arguments args) { HandleScope scope; // create a new handle scope ASSERT(args.length() == 3); CONVERT_CHECKED(JSRegExp, raw_re, args[0]); Handle<JSRegExp> re(raw_re); CONVERT_CHECKED(String, raw_pattern, args[1]); Handle<String> pattern(raw_pattern); CONVERT_CHECKED(String, raw_flags, args[2]); Handle<String> flags(raw_flags); return *RegExpImpl::JsreCompile(re, pattern, flags);}static Object* Runtime_CreateApiFunction(Arguments args) { HandleScope scope; ASSERT(args.length() == 1); CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]); Handle<FunctionTemplateInfo> data(raw_data); return *Factory::CreateApiFunction(data);}static Object* Runtime_IsTemplate(Arguments args) { ASSERT(args.length() == 1); Object* arg = args[0]; bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); return Heap::ToBoolean(result);}static Object* Runtime_GetTemplateField(Arguments args) { ASSERT(args.length() == 2); CONVERT_CHECKED(HeapObject, templ, args[0]); RUNTIME_ASSERT(templ->IsStruct()); CONVERT_CHECKED(Smi, field, args[1]); return HeapObject::GetHeapObjectField(templ, field->value());}static Object* ThrowRedeclarationError(const char* type, Handle<String> name) { HandleScope scope; Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type)); Handle<Object> args[2] = { type_handle, name }; Handle<Object> error = Factory::NewTypeError("redeclaration", HandleVector(args, 2)); return Top::Throw(*error);}static Object* Runtime_DeclareGlobals(Arguments args) { HandleScope scope; Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global()); CONVERT_ARG_CHECKED(FixedArray, pairs, 0); Handle<Context> context = args.at<Context>(1); bool is_eval = Smi::cast(args[2])->value() == 1; // Compute the property attributes. According to ECMA-262, section // 13, page 71, the property must be read-only and // non-deletable. However, neither SpiderMonkey nor KJS creates the // property as read-only, so we don't either. PropertyAttributes base = is_eval ? NONE : DONT_DELETE; // Only optimize the object if we intend to add more than 5 properties. OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5); // Traverse the name/value pairs and set the properties. int length = pairs->length(); for (int i = 0; i < length; i += 2) { HandleScope scope; Handle<String> name(String::cast(pairs->get(i))); Handle<Object> value(pairs->get(i + 1)); // We have to declare a global const property. To capture we only // assign to it when evaluating the assignment for "const x = // <expr>" the initial value is the hole. bool is_const_property = value->IsTheHole(); if (value->IsUndefined() || is_const_property) { // Lookup the property in the global object, and don't set the // value of the variable if the property is already there. LookupResult lookup; global->Lookup(*name, &lookup); if (lookup.IsProperty()) { // Determine if the property is local by comparing the holder // against the global object. The information will be used to // avoid throwing re-declaration errors when declaring // variables or constants that exist in the prototype chain. bool is_local = (*global == lookup.holder()); // Get the property attributes and determine if the property is // read-only. PropertyAttributes attributes = global->GetPropertyAttribute(*name); bool is_read_only = (attributes & READ_ONLY) != 0; if (lookup.type() == INTERCEPTOR) { // If the interceptor says the property is there, we // just return undefined without overwriting the property. // Otherwise, we continue to setting the property. if (attributes != ABSENT) { // Check if the existing property conflicts with regards to const. if (is_local && (is_read_only || is_const_property)) { const char* type = (is_read_only) ? "const" : "var"; return ThrowRedeclarationError(type, name); }; // The property already exists without conflicting: Go to // the next declaration. continue; } // Fall-through and introduce the absent property by using // SetProperty. } else { if (is_local && (is_read_only || is_const_property)) { const char* type = (is_read_only) ? "const" : "var"; return ThrowRedeclarationError(type, name); } // The property already exists without conflicting: Go to // the next declaration. continue; } } } else { // Copy the function and update its context. Use it as value. Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value); Handle<JSFunction> function = Factory::NewFunctionFromBoilerplate(boilerplate, context); value = function; } LookupResult lookup; global->LocalLookup(*name, &lookup); PropertyAttributes attributes = is_const_property ? static_cast<PropertyAttributes>(base | READ_ONLY) : base; if (lookup.IsProperty()) { // There's a local property that we need to overwrite because // we're either declaring a function or there's an interceptor // that claims the property is absent. // Check for conflicting re-declarations. We cannot have // conflicting types in case of intercepted properties because // they are absent. if (lookup.type() != INTERCEPTOR && (lookup.IsReadOnly() || is_const_property)) { const char* type = (lookup.IsReadOnly()) ? "const" : "var"; return ThrowRedeclarationError(type, name); } SetProperty(global, name, value, attributes); } else { // If a property with this name does not already exist on the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -