📄 builtins.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 "builtins.h"#include "ic-inl.h"namespace v8 { namespace internal {// ----------------------------------------------------------------------------// Support macros for defining builtins in C.// ----------------------------------------------------------------------------//// A builtin function is defined by writing://// BUILTIN(name) {// ...// }// BUILTIN_END//// In the body of the builtin function, the variable 'receiver' is visible.// The arguments can be accessed through://// BUILTIN_ARG(0): Receiver (also available as 'receiver')// BUILTIN_ARG(1): First argument// ...// BUILTIN_ARG(n): Last argument//// and they evaluate to undefined values if too few arguments were// passed to the builtin function invocation.//// __argc__ is the number of arguments including the receiver.// ----------------------------------------------------------------------------// TODO(1238487): We should consider passing whether or not the// builtin was invoked as a constructor as part of the// arguments. Maybe we also want to pass the called function?#define BUILTIN(name) \ static Object* Builtin_##name(int __argc__, Object** __argv__) { \ Handle<Object> receiver(&__argv__[0]);// Use an inline function to avoid evaluating the index (n) more than// once in the BUILTIN_ARG macro.static inline Object* __builtin_arg__(int n, int argc, Object** argv) { ASSERT(n >= 0); return (argc > n) ? argv[-n] : Heap::undefined_value();}// NOTE: Argument 0 is the receiver. The first 'real' argument is// argument 1 - BUILTIN_ARG(1).#define BUILTIN_ARG(n) (__builtin_arg__(n, __argc__, __argv__))#define BUILTIN_END \ return Heap::undefined_value(); \}// TODO(1238487): Get rid of this function that determines if the// builtin is called as a constructor. This may be a somewhat slow// operation due to the stack frame iteration.static inline bool CalledAsConstructor() { StackFrameIterator it; ASSERT(it.frame()->is_exit()); it.Advance(); StackFrame* frame = it.frame(); return frame->is_internal() && InternalFrame::cast(frame)->is_construct_trampoline();}// ----------------------------------------------------------------------------int Builtins::construct_call_pc_offset_ = 0;int Builtins::arguments_adaptor_call_pc_offset_ = 0;// Check if the builtin was called in a 'new' call.bool Builtins::IsConstructCall(Address pc) { ASSERT(construct_call_pc_offset_ > 0); int offset = pc - builtin(JSConstructCall)->address(); return offset == construct_call_pc_offset_;}bool Builtins::IsArgumentsAdaptorCall(Address pc) { ASSERT(arguments_adaptor_call_pc_offset_ > 0); int offset = pc - builtin(ArgumentsAdaptorTrampoline)->address(); return offset == arguments_adaptor_call_pc_offset_;}Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) { Code* code = Builtins::builtin(Builtins::Illegal); *resolved = false; if (Top::security_context() != NULL) { Object* object = Top::security_context_builtins()->javascript_builtin(id); if (object->IsJSFunction()) { Handle<JSFunction> function(JSFunction::cast(object)); // Make sure the number of parameters match the formal parameter count. ASSERT(function->shared()->formal_parameter_count() == Builtins::GetArgumentsCount(id)); if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) { code = function->code(); *resolved = true; } } } return Handle<Code>(code);}BUILTIN(Illegal) { UNREACHABLE();}BUILTIN_ENDBUILTIN(EmptyFunction) {}BUILTIN_ENDBUILTIN(ArrayCode) { JSArray* array; if (CalledAsConstructor()) { array = JSArray::cast(*receiver); } else { // Allocate the JS Array JSFunction* constructor = Top::context()->global_context()->array_function(); Object* obj = Heap::AllocateJSObject(constructor); if (obj->IsFailure()) return obj; array = JSArray::cast(obj); } // 'array' now contains the JSArray we should initialize. // Optimize the case where there is one argument and the argument is a // small smi. if (__argc__ == 2) { Object* obj = BUILTIN_ARG(1); if (obj->IsSmi()) { int len = Smi::cast(obj)->value(); if (len >= 0 && len < JSObject::kMaxFastElementsLength) { Object* obj = Heap::AllocateFixedArrayWithHoles(len); if (obj->IsFailure()) return obj; array->SetContent(FixedArray::cast(obj)); return array; } } // Take the argument as the length. obj = array->Initialize(0); if (obj->IsFailure()) return obj; if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1)); } // Optimize the case where there are no parameters passed. if (__argc__ == 1) return array->Initialize(4); // Take the arguments as elements. int number_of_elements = __argc__ - 1; Smi* len = Smi::FromInt(number_of_elements); Object* obj = Heap::AllocateFixedArrayWithHoles(len->value()); if (obj->IsFailure()) return obj; FixedArray* elms = FixedArray::cast(obj); FixedArray::WriteBarrierMode mode = elms->GetWriteBarrierMode(); // Fill in the content for (int index = 0; index < number_of_elements; index++) { elms->set(index, BUILTIN_ARG(index+1), mode); } // Set length and elements on the array. array->set_elements(FixedArray::cast(obj)); array->set_length(len); return array;}BUILTIN_ENDBUILTIN(ArrayPush) { JSArray* array = JSArray::cast(*receiver); ASSERT(array->HasFastElements()); // Make sure we have space for the elements. int len = Smi::cast(array->length())->value(); // Set new length. int new_length = len + __argc__ - 1; FixedArray* elms = FixedArray::cast(array->elements()); if (new_length <= elms->length()) { // Backing storage has extra space for the provided values. for (int index = 0; index < __argc__ - 1; index++) { elms->set(index + len, BUILTIN_ARG(index+1)); } } else { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); if (obj->IsFailure()) return obj; FixedArray* new_elms = FixedArray::cast(obj); FixedArray::WriteBarrierMode mode = new_elms->GetWriteBarrierMode(); // Fill out the new array with old elements. for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode); // Add the provided values. for (int index = 0; index < __argc__ - 1; index++) { new_elms->set(index + len, BUILTIN_ARG(index+1), mode); } // Set the new backing storage. array->set_elements(new_elms); } // Set the length. array->set_length(Smi::FromInt(new_length)); return array->length();}BUILTIN_ENDBUILTIN(ArrayPop) { JSArray* array = JSArray::cast(*receiver); ASSERT(array->HasFastElements()); Object* undefined = Heap::undefined_value(); int len = Smi::cast(array->length())->value(); if (len == 0) return undefined; // Get top element FixedArray* elms = FixedArray::cast(array->elements()); Object* top = elms->get(len - 1); // Set the length. array->set_length(Smi::FromInt(len - 1)); if (!top->IsTheHole()) { // Delete the top element. elms->set_the_hole(len - 1); return top; } // Remember to check the prototype chain. JSFunction* array_function = Top::context()->global_context()->array_function(); JSObject* prototype = JSObject::cast(array_function->prototype()); top = prototype->GetElement(len - 1); return top;}BUILTIN_END// -----------------------------------------------------------------------------//// Returns the holder JSObject if the function can legally be called// with this receiver. Returns Heap::null_value() if the call is// illegal. Any arguments that don't fit the expected type is// overwritten with undefined. Arguments that do fit the expected// type is overwritten with the object in the prototype chain that// actually has that type.static inline Object* TypeCheck(int argc, Object** argv, FunctionTemplateInfo* info) { Object* recv = argv[0]; Object* sig_obj = info->signature(); if (sig_obj->IsUndefined()) return recv; SignatureInfo* sig = SignatureInfo::cast(sig_obj); // If necessary, check the receiver Object* recv_type = sig->receiver(); Object* holder = recv; if (!recv_type->IsUndefined()) { for (; holder != Heap::null_value(); holder = holder->GetPrototype()) { if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) { break; } } if (holder == Heap::null_value()) return holder; } Object* args_obj = sig->args(); // If there is no argument signature we're done if (args_obj->IsUndefined()) return holder; FixedArray* args = FixedArray::cast(args_obj); int length = args->length(); if (argc <= length) length = argc - 1; for (int i = 0; i < length; i++) { Object* argtype = args->get(i); if (argtype->IsUndefined()) continue; Object** arg = &argv[-1 - i]; Object* current = *arg; for (; current != Heap::null_value(); current = current->GetPrototype()) { if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) { *arg = current; break; } } if (current == Heap::null_value()) *arg = Heap::undefined_value(); } return holder;}BUILTIN(HandleApiCall) { HandleScope scope; bool is_construct = CalledAsConstructor(); // TODO(1238487): This is not nice. We need to get rid of this // kludgy behavior and start handling API calls in a more direct // way - maybe compile specialized stubs lazily?. Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function)); if (is_construct) { Handle<FunctionTemplateInfo> desc = Handle<FunctionTemplateInfo>( FunctionTemplateInfo::cast(function->shared()->function_data())); bool pending_exception = false; Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver), &pending_exception); ASSERT(Top::has_pending_exception() == pending_exception); if (pending_exception) return Failure::Exception(); } FunctionTemplateInfo* fun_data = FunctionTemplateInfo::cast(function->shared()->function_data());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -