__ 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();
__ 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);
}
#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) \
\
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);
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);
__ 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();
__ 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);
}
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)
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);
}
// [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();
// (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;
}
+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;
}
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.