Author: [email protected]
Date: Fri Jun 19 00:36:16 2009
New Revision: 2222

Modified:
    branches/bleeding_edge/src/arm/builtins-arm.cc
    branches/bleeding_edge/src/builtins.h
    branches/bleeding_edge/src/heap.cc
    branches/bleeding_edge/src/ia32/builtins-ia32.cc
    branches/bleeding_edge/src/objects-inl.h
    branches/bleeding_edge/src/objects.cc
    branches/bleeding_edge/src/objects.h
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/src/x64/builtins-x64.cc

Log:
Allow functions to have custom construct stubs that are called
when the function is instantiated.
Review URL: http://codereview.chromium.org/132063

Modified: branches/bleeding_edge/src/arm/builtins-arm.cc
==============================================================================
--- branches/bleeding_edge/src/arm/builtins-arm.cc      (original)
+++ branches/bleeding_edge/src/arm/builtins-arm.cc      Fri Jun 19 00:36:16 2009
@@ -67,6 +67,24 @@
    __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
    __ b(ne, &non_function_call);

+  // Jump to the function-specific construct stub.
+  __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+  __ ldr(r2, FieldMemOperand(r2,  
SharedFunctionInfo::kConstructStubOffset));
+  __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // r0: number of arguments
+  // r1: called object
+  __ bind(&non_function_call);
+
+  // Set expected number of arguments to zero (not changing r0).
+  __ mov(r2, Operand(0));
+  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
+  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+          RelocInfo::CODE_TARGET);
+}
+
+
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
    // Enter a construct frame.
    __ EnterConstructFrame();

@@ -177,16 +195,6 @@
    __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
    __ add(sp, sp, Operand(kPointerSize));
    __ Jump(lr);
-
-  // r0: number of arguments
-  // r1: called object
-  __ bind(&non_function_call);
-
-  // Set expected number of arguments to zero (not changing r0).
-  __ mov(r2, Operand(0));
-  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
-  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
-          RelocInfo::CODE_TARGET);
  }



Modified: branches/bleeding_edge/src/builtins.h
==============================================================================
--- branches/bleeding_edge/src/builtins.h       (original)
+++ branches/bleeding_edge/src/builtins.h       Fri Jun 19 00:36:16 2009
@@ -51,6 +51,7 @@
  #define BUILTIN_LIST_A(V)                                      \
    V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED)        \
    V(JSConstructCall,            BUILTIN, UNINITIALIZED)        \
+  V(JSConstructStubGeneric,     BUILTIN, UNINITIALIZED)        \
    V(JSEntryTrampoline,          BUILTIN, UNINITIALIZED)        \
    V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED)        \
                                                                 \
@@ -210,6 +211,7 @@

    static void Generate_Adaptor(MacroAssembler* masm, CFunctionId id);
    static void Generate_JSConstructCall(MacroAssembler* masm);
+  static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
    static void Generate_JSEntryTrampoline(MacroAssembler* masm);
    static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
    static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);

Modified: branches/bleeding_edge/src/heap.cc
==============================================================================
--- branches/bleeding_edge/src/heap.cc  (original)
+++ branches/bleeding_edge/src/heap.cc  Fri Jun 19 00:36:16 2009
@@ -1510,6 +1510,8 @@
    share->set_name(name);
    Code* illegal = Builtins::builtin(Builtins::Illegal);
    share->set_code(illegal);
+  Code* construct_stub =  
Builtins::builtin(Builtins::JSConstructStubGeneric);
+  share->set_construct_stub(construct_stub);
    share->set_expected_nof_properties(0);
    share->set_length(0);
    share->set_formal_parameter_count(0);

Modified: branches/bleeding_edge/src/ia32/builtins-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/builtins-ia32.cc    (original)
+++ branches/bleeding_edge/src/ia32/builtins-ia32.cc    Fri Jun 19 00:36:16  
2009
@@ -63,6 +63,25 @@
    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
    __ j(not_equal, &non_function_call);

+  // Jump to the function-specific construct stub.
+  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
+  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
+  __ jmp(Operand(ebx));
+
+  // edi: called object
+  // eax: number of arguments
+  __ bind(&non_function_call);
+
+  // Set expected number of arguments to zero (not changing eax).
+  __ Set(ebx, Immediate(0));
+  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
+  __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+         RelocInfo::CODE_TARGET);
+}
+
+
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
    // Enter a construct frame.
    __ EnterConstructFrame();

@@ -305,16 +324,6 @@
    __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~  
receiver
    __ push(ecx);
    __ ret(0);
-
-  // edi: called object
-  // eax: number of arguments
-  __ bind(&non_function_call);
-
-  // Set expected number of arguments to zero (not changing eax).
-  __ Set(ebx, Immediate(0));
-  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
-  __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
-         RelocInfo::CODE_TARGET);
  }



Modified: branches/bleeding_edge/src/objects-inl.h
==============================================================================
--- branches/bleeding_edge/src/objects-inl.h    (original)
+++ branches/bleeding_edge/src/objects-inl.h    Fri Jun 19 00:36:16 2009
@@ -2130,6 +2130,7 @@
  ACCESSORS(BreakPointInfo, break_point_objects, Object,  
kBreakPointObjectsIndex)
  #endif

+ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset)
  ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset)
  ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
            kInstanceClassNameOffset)

Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc       (original)
+++ branches/bleeding_edge/src/objects.cc       Fri Jun 19 00:36:16 2009
@@ -4632,7 +4632,7 @@


  void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
-  IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
+  IteratePointers(v, kNameOffset, kConstructStubOffset + kPointerSize);
    IteratePointers(v, kInstanceClassNameOffset, kScriptOffset +  
kPointerSize);
    IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
  }

Modified: branches/bleeding_edge/src/objects.h
==============================================================================
--- branches/bleeding_edge/src/objects.h        (original)
+++ branches/bleeding_edge/src/objects.h        Fri Jun 19 00:36:16 2009
@@ -2743,6 +2743,9 @@
    // [code]: Function code.
    DECL_ACCESSORS(code, Code)

+  // [construct stub]: Code stub for constructing instances of this  
function.
+  DECL_ACCESSORS(construct_stub, Code)
+
    // Returns if this function has been compiled to native code yet.
    inline bool is_compiled();

@@ -2838,7 +2841,8 @@
    // (An even number of integers has a size that is a multiple of a  
pointer.)
    static const int kNameOffset = HeapObject::kHeaderSize;
    static const int kCodeOffset = kNameOffset + kPointerSize;
-  static const int kLengthOffset = kCodeOffset + kPointerSize;
+  static const int kConstructStubOffset = kCodeOffset + kPointerSize;
+  static const int kLengthOffset = kConstructStubOffset + kPointerSize;
    static const int kFormalParameterCountOffset = kLengthOffset + kIntSize;
    static const int kExpectedNofPropertiesOffset =
        kFormalParameterCountOffset + kIntSize;

Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Fri Jun 19 00:36:16 2009
@@ -4328,45 +4328,61 @@
  }


+static Handle<Code> ComputeConstructStub(Handle<Map> map) {
+  // TODO(385): Change this to create a construct stub specialized for
+  // the given map to make allocation of simple objects - and maybe
+  // arrays - much faster.
+  return Handle<Code>(Builtins::builtin(Builtins::JSConstructStubGeneric));
+}
+
+
  static Object* Runtime_NewObject(Arguments args) {
-  NoHandleAllocation ha;
+  HandleScope scope;
    ASSERT(args.length() == 1);

-  Object* constructor = args[0];
-  if (constructor->IsJSFunction()) {
-    JSFunction* function = JSFunction::cast(constructor);
+  Handle<Object> constructor = args.at<Object>(0);
+
+  // If the constructor isn't a proper function we throw a type error.
+  if (!constructor->IsJSFunction()) {
+    Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
+    Handle<Object> type_error =
+        Factory::NewTypeError("not_constructor", arguments);
+    return Top::Throw(*type_error);
+  }

-    // Handle stepping into constructors if step into is active.
+  Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
  #ifdef ENABLE_DEBUGGER_SUPPORT
-    if (Debug::StepInActive()) {
-      HandleScope scope;
-      Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
-    }
+  // Handle stepping into constructors if step into is active.
+  if (Debug::StepInActive()) {
+    Debug::HandleStepIn(function, 0, true);
+  }
  #endif

-    if (function->has_initial_map() &&
-        function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
+  if (function->has_initial_map()) {
+    if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
        // The 'Function' function ignores the receiver object when
        // called using 'new' and creates a new JSFunction object that
        // is returned.  The receiver object is only used for error
        // reporting if an error occurs when constructing the new
-      // JSFunction.  AllocateJSObject should not be used to allocate
-      // JSFunctions since it does not properly initialize the shared
-      // part of the function.  Since the receiver is ignored anyway,
-      // we use the global object as the receiver instead of a new
-      // JSFunction object.  This way, errors are reported the same
-      // way whether or not 'Function' is called using 'new'.
+      // JSFunction. Factory::NewJSObject() should not be used to
+      // allocate JSFunctions since it does not properly initialize
+      // the shared part of the function. Since the receiver is
+      // ignored anyway, we use the global object as the receiver
+      // instead of a new JSFunction object. This way, errors are
+      // reported the same way whether or not 'Function' is called
+      // using 'new'.
        return Top::context()->global();
      }
-    return Heap::AllocateJSObject(function);
    }

-  HandleScope scope;
-  Handle<Object> cons(constructor);
-  // The constructor is not a function; throw a type error.
-  Handle<Object> type_error =
-    Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
-  return Top::Throw(*type_error);
+  bool first_allocation = !function->has_initial_map();
+  Handle<JSObject> result = Factory::NewJSObject(function);
+  if (first_allocation) {
+    Handle<Map> map = Handle<Map>(function->initial_map());
+    Handle<Code> stub = ComputeConstructStub(map);
+    function->shared()->set_construct_stub(*stub);
+  }
+  return *result;
  }



Modified: branches/bleeding_edge/src/x64/builtins-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/builtins-x64.cc      (original)
+++ branches/bleeding_edge/src/x64/builtins-x64.cc      Fri Jun 19 00:36:16 2009
@@ -171,6 +171,10 @@
    masm->int3();  // UNIMPLEMENTED.
  }

+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  masm->int3();  // UNIMPLEMENTED.
+}
+
  static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
                                               bool is_construct) {
    // Expects five C++ function parameters.

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to