[es6] Introduce spec compliant IsConstructor.
There was already a bit on the Map named "function with prototype", which basically meant that the Map was a map for a JSFunction that could be used as a constructor. Now this CL generalizes that bit to IsConstructor, which says that whatever (Heap)Object you are looking at can be used as a constructor (i.e. the bit is also set for bound functions that can be used as constructors and proxies that have a [[Construct]] internal method). This way we have a single chokepoint for IsConstructor checking, which allows us to get rid of the various ways in which we tried to guess whether something could be used as a constructor or not. Drive-by-fix: Renamed IsConstructor on FunctionKind to IsClassConstructor to resolve the weird name clash, and the IsClassConstructor name also matches the spec. R=jarin@chromium.org, rossberg@chromium.org BUG=v8:4430 LOG=n Review URL: https://codereview.chromium.org/1358423002 Cr-Commit-Position: refs/heads/master@{#30900}
This commit is contained in:
parent
5ced12c154
commit
8de4d9351d
@ -929,7 +929,7 @@ MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype(
|
|||||||
|
|
||||||
MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
|
MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
|
||||||
Handle<Object> prototype) {
|
Handle<Object> prototype) {
|
||||||
DCHECK(function->should_have_prototype());
|
DCHECK(function->IsConstructor());
|
||||||
Isolate* isolate = function->GetIsolate();
|
Isolate* isolate = function->GetIsolate();
|
||||||
return SetFunctionPrototype(isolate, function, prototype);
|
return SetFunctionPrototype(isolate, function, prototype);
|
||||||
}
|
}
|
||||||
|
@ -494,6 +494,7 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
|
|||||||
// Mark instance as callable in the map.
|
// Mark instance as callable in the map.
|
||||||
if (!obj->instance_call_handler()->IsUndefined()) {
|
if (!obj->instance_call_handler()->IsUndefined()) {
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
|
map->set_is_constructor(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively copy parent instance templates' accessors,
|
// Recursively copy parent instance templates' accessors,
|
||||||
|
@ -1635,6 +1635,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r0 : the number of arguments (not including the receiver)
|
||||||
|
// -- r1 : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -- r3 : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1644,35 +1659,35 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// the JSFunction on which new was invoked initially)
|
// the JSFunction on which new was invoked initially)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(r1, &non_callable);
|
Label non_constructor;
|
||||||
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
|
__ JumpIfSmi(r1, &non_constructor);
|
||||||
|
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||||
|
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
|
||||||
|
__ tst(r2, Operand(1 << Map::kIsConstructor));
|
||||||
|
__ b(eq, &non_constructor);
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ CompareInstanceType(r4, r5, JS_FUNCTION_TYPE);
|
||||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET, eq);
|
RelocInfo::CODE_TARGET, eq);
|
||||||
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
|
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
|
||||||
__ b(ne, &non_function);
|
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||||
|
eq);
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something that else, which might have a [[Construct]]
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// internal method (if not we raise an exception).
|
// method.
|
||||||
__ bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
|
|
||||||
__ tst(r4, Operand(1 << Map::kIsCallable));
|
|
||||||
__ b(eq, &non_callable);
|
|
||||||
// Overwrite the original receiver the (original) target.
|
|
||||||
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(r1);
|
__ Push(r1);
|
||||||
|
@ -1692,6 +1692,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- x0 : the number of arguments (not including the receiver)
|
||||||
|
// -- x1 : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -- x3 : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1701,34 +1716,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// the JSFunction on which new was invoked initially)
|
// the JSFunction on which new was invoked initially)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(x1, &non_callable);
|
Label non_constructor;
|
||||||
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
|
__ JumpIfSmi(x1, &non_constructor);
|
||||||
|
__ Ldr(x4, FieldMemOperand(x1, HeapObject::kMapOffset));
|
||||||
|
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
|
||||||
|
__ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ CompareInstanceType(x4, x5, JS_FUNCTION_TYPE);
|
||||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET, eq);
|
RelocInfo::CODE_TARGET, eq);
|
||||||
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
|
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
|
||||||
__ B(ne, &non_function);
|
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||||
|
eq);
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something that else, which might have a [[Construct]]
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// internal method (if not we raise an exception).
|
// method.
|
||||||
__ Bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
|
|
||||||
__ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
|
|
||||||
// Overwrite the original receiver with the (original) target.
|
|
||||||
__ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(x1);
|
__ Push(x1);
|
||||||
|
@ -487,7 +487,7 @@ void Genesis::SetFunctionInstanceDescriptor(Handle<Map> map,
|
|||||||
Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
|
Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
|
||||||
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||||
SetFunctionInstanceDescriptor(map, function_mode);
|
SetFunctionInstanceDescriptor(map, function_mode);
|
||||||
map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
|
map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
@ -727,7 +727,7 @@ Handle<Map> Genesis::CreateStrictFunctionMap(
|
|||||||
FunctionMode function_mode, Handle<JSFunction> empty_function) {
|
FunctionMode function_mode, Handle<JSFunction> empty_function) {
|
||||||
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||||
SetStrictFunctionInstanceDescriptor(map, function_mode);
|
SetStrictFunctionInstanceDescriptor(map, function_mode);
|
||||||
map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
|
map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
Map::SetPrototype(map, empty_function);
|
Map::SetPrototype(map, empty_function);
|
||||||
return map;
|
return map;
|
||||||
@ -738,7 +738,7 @@ Handle<Map> Genesis::CreateStrongFunctionMap(
|
|||||||
Handle<JSFunction> empty_function, bool is_constructor) {
|
Handle<JSFunction> empty_function, bool is_constructor) {
|
||||||
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||||
SetStrongFunctionInstanceDescriptor(map);
|
SetStrongFunctionInstanceDescriptor(map);
|
||||||
map->set_function_with_prototype(is_constructor);
|
map->set_is_constructor(is_constructor);
|
||||||
Map::SetPrototype(map, empty_function);
|
Map::SetPrototype(map, empty_function);
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
map->set_is_extensible(is_constructor);
|
map->set_is_extensible(is_constructor);
|
||||||
@ -1373,7 +1373,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
|||||||
}
|
}
|
||||||
// @@iterator method is added later.
|
// @@iterator method is added later.
|
||||||
|
|
||||||
map->set_function_with_prototype(true);
|
map->set_is_constructor(true);
|
||||||
map->SetInObjectProperties(2);
|
map->SetInObjectProperties(2);
|
||||||
native_context()->set_sloppy_arguments_map(*map);
|
native_context()->set_sloppy_arguments_map(*map);
|
||||||
|
|
||||||
@ -1439,7 +1439,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
|||||||
}
|
}
|
||||||
// @@iterator method is added later.
|
// @@iterator method is added later.
|
||||||
|
|
||||||
map->set_function_with_prototype(true);
|
map->set_is_constructor(true);
|
||||||
DCHECK_EQ(native_context()->object_function()->prototype(),
|
DCHECK_EQ(native_context()->object_function()->prototype(),
|
||||||
*isolate->initial_object_prototype());
|
*isolate->initial_object_prototype());
|
||||||
Map::SetPrototype(map, isolate->initial_object_prototype());
|
Map::SetPrototype(map, isolate->initial_object_prototype());
|
||||||
|
@ -78,6 +78,7 @@ enum BuiltinExtraArguments {
|
|||||||
V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||||
\
|
\
|
||||||
V(ConstructFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
V(ConstructFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||||
|
V(ConstructProxy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||||
V(Construct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
V(Construct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||||
\
|
\
|
||||||
V(PushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
V(PushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||||
@ -281,6 +282,8 @@ class Builtins {
|
|||||||
|
|
||||||
// ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget)
|
// ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget)
|
||||||
static void Generate_ConstructFunction(MacroAssembler* masm);
|
static void Generate_ConstructFunction(MacroAssembler* masm);
|
||||||
|
// ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget)
|
||||||
|
static void Generate_ConstructProxy(MacroAssembler* masm);
|
||||||
// ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget])
|
// ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget])
|
||||||
static void Generate_Construct(MacroAssembler* masm);
|
static void Generate_Construct(MacroAssembler* masm);
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ class Context: public FixedArray {
|
|||||||
: SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
|
: SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConstructor(kind)) {
|
if (IsClassConstructor(kind)) {
|
||||||
// Use strict function map (no own "caller" / "arguments")
|
// Use strict function map (no own "caller" / "arguments")
|
||||||
return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX
|
return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX
|
||||||
: STRICT_FUNCTION_MAP_INDEX;
|
: STRICT_FUNCTION_MAP_INDEX;
|
||||||
|
@ -1930,6 +1930,7 @@ Handle<JSProxy> Factory::NewJSFunctionProxy(Handle<Object> handler,
|
|||||||
Handle<Map> map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
|
Handle<Map> map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
|
||||||
Map::SetPrototype(map, prototype);
|
Map::SetPrototype(map, prototype);
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
|
map->set_is_constructor(construct_trap->IsCallable());
|
||||||
|
|
||||||
// Allocate the proxy object.
|
// Allocate the proxy object.
|
||||||
Handle<JSFunctionProxy> result = New<JSFunctionProxy>(map, NEW_SPACE);
|
Handle<JSFunctionProxy> result = New<JSFunctionProxy>(map, NEW_SPACE);
|
||||||
@ -1991,7 +1992,7 @@ void Factory::ReinitializeJSProxy(Handle<JSProxy> proxy, InstanceType type,
|
|||||||
|
|
||||||
// Functions require some minimal initialization.
|
// Functions require some minimal initialization.
|
||||||
if (type == JS_FUNCTION_TYPE) {
|
if (type == JS_FUNCTION_TYPE) {
|
||||||
map->set_function_with_prototype(true);
|
map->set_is_constructor(true);
|
||||||
map->set_is_callable();
|
map->set_is_callable();
|
||||||
Handle<JSFunction> js_function = Handle<JSFunction>::cast(proxy);
|
Handle<JSFunction> js_function = Handle<JSFunction>::cast(proxy);
|
||||||
InitializeFunction(js_function, shared.ToHandleChecked(), context);
|
InitializeFunction(js_function, shared.ToHandleChecked(), context);
|
||||||
|
@ -997,7 +997,7 @@ inline bool IsSubclassConstructor(FunctionKind kind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool IsConstructor(FunctionKind kind) {
|
inline bool IsClassConstructor(FunctionKind kind) {
|
||||||
DCHECK(IsValidFunctionKind(kind));
|
DCHECK(IsValidFunctionKind(kind));
|
||||||
return kind &
|
return kind &
|
||||||
(FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
|
(FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
|
||||||
|
@ -6418,7 +6418,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
|||||||
if (!CanInlinePropertyAccess(map_)) return false;
|
if (!CanInlinePropertyAccess(map_)) return false;
|
||||||
if (IsJSObjectFieldAccessor()) return IsLoad();
|
if (IsJSObjectFieldAccessor()) return IsLoad();
|
||||||
if (IsJSArrayBufferViewFieldAccessor()) return IsLoad();
|
if (IsJSArrayBufferViewFieldAccessor()) return IsLoad();
|
||||||
if (map_->function_with_prototype() && !map_->has_non_instance_prototype() &&
|
if (map_->IsJSFunctionMap() && map_->is_constructor() &&
|
||||||
|
!map_->has_non_instance_prototype() &&
|
||||||
name_.is_identical_to(isolate()->factory()->prototype_string())) {
|
name_.is_identical_to(isolate()->factory()->prototype_string())) {
|
||||||
return IsLoad();
|
return IsLoad();
|
||||||
}
|
}
|
||||||
@ -6532,7 +6533,7 @@ HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
|
if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
|
||||||
info->map()->function_with_prototype()) {
|
info->map()->IsJSFunctionMap() && info->map()->is_constructor()) {
|
||||||
DCHECK(!info->map()->has_non_instance_prototype());
|
DCHECK(!info->map()->has_non_instance_prototype());
|
||||||
return New<HLoadFunctionPrototype>(checked_object);
|
return New<HLoadFunctionPrototype>(checked_object);
|
||||||
}
|
}
|
||||||
|
@ -1566,6 +1566,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : the number of arguments (not including the receiver)
|
||||||
|
// -- edx : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -- edi : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1575,34 +1590,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// -- edi : the constructor to call (can be any Object)
|
// -- edi : the constructor to call (can be any Object)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(edi, &non_callable);
|
Label non_constructor;
|
||||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
__ JumpIfSmi(edi, &non_constructor, Label::kNear);
|
||||||
|
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
|
||||||
|
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
|
||||||
|
__ j(zero, &non_constructor, Label::kNear);
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ CmpInstanceType(ecx, JS_FUNCTION_TYPE);
|
||||||
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET);
|
RelocInfo::CODE_TARGET);
|
||||||
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
|
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
|
||||||
__ j(not_equal, &non_function, Label::kNear);
|
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something else, which might have a [[Construct]] internal
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// method (if not we raise an exception).
|
// method.
|
||||||
__ bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
|
|
||||||
__ j(zero, &non_callable, Label::kNear);
|
|
||||||
// Overwrite the original receiver with the (original) target.
|
|
||||||
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(edi);
|
__ Push(edi);
|
||||||
|
@ -1159,7 +1159,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
|||||||
// Use specialized code for getting prototype of functions.
|
// Use specialized code for getting prototype of functions.
|
||||||
if (receiver->IsJSFunction() &&
|
if (receiver->IsJSFunction() &&
|
||||||
Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
|
Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
|
||||||
Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
|
receiver->IsConstructor() &&
|
||||||
!Handle<JSFunction>::cast(receiver)
|
!Handle<JSFunction>::cast(receiver)
|
||||||
->map()
|
->map()
|
||||||
->has_non_instance_prototype()) {
|
->has_non_instance_prototype()) {
|
||||||
|
@ -1648,6 +1648,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- a0 : the number of arguments (not including the receiver)
|
||||||
|
// -- a1 : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -- a3 : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1657,36 +1672,36 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// the JSFunction on which new was invoked initially)
|
// the JSFunction on which new was invoked initially)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(a1, &non_callable);
|
Label non_constructor;
|
||||||
__ GetObjectType(a1, t1, t2);
|
__ JumpIfSmi(a1, &non_constructor);
|
||||||
|
__ lw(t1, FieldMemOperand(t1, HeapObject::kMapOffset));
|
||||||
|
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
|
||||||
|
__ And(t2, t2, Operand(1 << Map::kIsCallable));
|
||||||
|
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
||||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
||||||
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
|
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||||
|
eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ sll(at, a0, kPointerSizeLog2);
|
||||||
|
__ addu(at, sp, at);
|
||||||
|
__ sw(a1, MemOperand(at));
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something that else, which might have a [[Construct]]
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// internal method (if not we raise an exception).
|
// method.
|
||||||
__ bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
|
|
||||||
__ And(t1, t1, Operand(1 << Map::kIsCallable));
|
|
||||||
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
|
|
||||||
// Overwrite the original receiver with the (original) target.
|
|
||||||
__ sll(at, a0, kPointerSizeLog2);
|
|
||||||
__ addu(at, sp, at);
|
|
||||||
__ sw(a1, MemOperand(at));
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(a1);
|
__ Push(a1);
|
||||||
|
@ -1644,6 +1644,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- a0 : the number of arguments (not including the receiver)
|
||||||
|
// -- a1 : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -- a3 : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1653,36 +1668,36 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// the JSFunction on which new was invoked initially)
|
// the JSFunction on which new was invoked initially)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(a1, &non_callable);
|
Label non_constructor;
|
||||||
__ GetObjectType(a1, t1, t2);
|
__ JumpIfSmi(a1, &non_constructor);
|
||||||
|
__ ld(t1, FieldMemOperand(t1, HeapObject::kMapOffset));
|
||||||
|
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
|
||||||
|
__ And(t2, t2, Operand(1 << Map::kIsCallable));
|
||||||
|
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
||||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
||||||
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
|
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||||
|
eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ dsll(at, a0, kPointerSizeLog2);
|
||||||
|
__ daddu(at, sp, at);
|
||||||
|
__ sd(a1, MemOperand(at));
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something that else, which might have a [[Construct]]
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// internal method (if not we raise an exception).
|
// method.
|
||||||
__ bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
|
|
||||||
__ And(t1, t1, Operand(1 << Map::kIsCallable));
|
|
||||||
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
|
|
||||||
// Overwrite the original receiver with the (original) target.
|
|
||||||
__ dsll(at, a0, kPointerSizeLog2);
|
|
||||||
__ daddu(at, sp, at);
|
|
||||||
__ sd(a1, MemOperand(at));
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(a1);
|
__ Push(a1);
|
||||||
|
@ -192,6 +192,12 @@ bool Object::IsCallable() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Object::IsConstructor() const {
|
||||||
|
return Object::IsHeapObject() &&
|
||||||
|
HeapObject::cast(this)->map()->is_constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Object::IsSpecObject() const {
|
bool Object::IsSpecObject() const {
|
||||||
return Object::IsHeapObject()
|
return Object::IsHeapObject()
|
||||||
&& HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE;
|
&& HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE;
|
||||||
@ -4532,13 +4538,17 @@ bool Map::has_non_instance_prototype() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::set_function_with_prototype(bool value) {
|
void Map::set_is_constructor(bool value) {
|
||||||
set_bit_field(FunctionWithPrototype::update(bit_field(), value));
|
if (value) {
|
||||||
|
set_bit_field(bit_field() | (1 << kIsConstructor));
|
||||||
|
} else {
|
||||||
|
set_bit_field(bit_field() & ~(1 << kIsConstructor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Map::function_with_prototype() {
|
bool Map::is_constructor() const {
|
||||||
return FunctionWithPrototype::decode(bit_field());
|
return ((1 << kIsConstructor) & bit_field()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4795,6 +4805,7 @@ bool Map::IsJSObjectMap() {
|
|||||||
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
||||||
}
|
}
|
||||||
bool Map::IsJSArrayMap() { return instance_type() == JS_ARRAY_TYPE; }
|
bool Map::IsJSArrayMap() { return instance_type() == JS_ARRAY_TYPE; }
|
||||||
|
bool Map::IsJSFunctionMap() { return instance_type() == JS_FUNCTION_TYPE; }
|
||||||
bool Map::IsStringMap() { return instance_type() < FIRST_NONSTRING_TYPE; }
|
bool Map::IsStringMap() { return instance_type() < FIRST_NONSTRING_TYPE; }
|
||||||
bool Map::IsJSProxyMap() {
|
bool Map::IsJSProxyMap() {
|
||||||
InstanceType type = instance_type();
|
InstanceType type = instance_type();
|
||||||
@ -6256,11 +6267,6 @@ Object* JSFunction::prototype() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JSFunction::should_have_prototype() {
|
|
||||||
return map()->function_with_prototype();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool JSFunction::is_compiled() {
|
bool JSFunction::is_compiled() {
|
||||||
Builtins* builtins = GetIsolate()->builtins();
|
Builtins* builtins = GetIsolate()->builtins();
|
||||||
return code() != builtins->builtin(Builtins::kCompileLazy) &&
|
return code() != builtins->builtin(Builtins::kCompileLazy) &&
|
||||||
|
@ -10719,7 +10719,7 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
|
|||||||
|
|
||||||
void JSFunction::SetPrototype(Handle<JSFunction> function,
|
void JSFunction::SetPrototype(Handle<JSFunction> function,
|
||||||
Handle<Object> value) {
|
Handle<Object> value) {
|
||||||
DCHECK(function->should_have_prototype());
|
DCHECK(function->IsConstructor());
|
||||||
Handle<Object> construct_prototype = value;
|
Handle<Object> construct_prototype = value;
|
||||||
|
|
||||||
// If the value is not a JSReceiver, store the value in the map's
|
// If the value is not a JSReceiver, store the value in the map's
|
||||||
|
@ -1033,6 +1033,9 @@ class Object {
|
|||||||
// ES6, section 7.2.3 IsCallable.
|
// ES6, section 7.2.3 IsCallable.
|
||||||
INLINE(bool IsCallable() const);
|
INLINE(bool IsCallable() const);
|
||||||
|
|
||||||
|
// ES6, section 7.2.4 IsConstructor.
|
||||||
|
INLINE(bool IsConstructor() const);
|
||||||
|
|
||||||
INLINE(bool IsSpecObject()) const;
|
INLINE(bool IsSpecObject()) const;
|
||||||
INLINE(bool IsTemplateInfo()) const;
|
INLINE(bool IsTemplateInfo()) const;
|
||||||
INLINE(bool IsNameDictionary() const);
|
INLINE(bool IsNameDictionary() const);
|
||||||
@ -5362,11 +5365,10 @@ class Map: public HeapObject {
|
|||||||
inline void set_non_instance_prototype(bool value);
|
inline void set_non_instance_prototype(bool value);
|
||||||
inline bool has_non_instance_prototype();
|
inline bool has_non_instance_prototype();
|
||||||
|
|
||||||
// Tells whether function has special prototype property. If not, prototype
|
// Tells whether the instance has a [[Construct]] internal method.
|
||||||
// property will not be created when accessed (will return undefined),
|
// This property is implemented according to ES6, section 7.2.4.
|
||||||
// and construction from this function will not be allowed.
|
inline void set_is_constructor(bool value);
|
||||||
inline void set_function_with_prototype(bool value);
|
inline bool is_constructor() const;
|
||||||
inline bool function_with_prototype();
|
|
||||||
|
|
||||||
// Tells whether the instance with this map should be ignored by the
|
// Tells whether the instance with this map should be ignored by the
|
||||||
// Object.getPrototypeOf() function and the __proto__ accessor.
|
// Object.getPrototypeOf() function and the __proto__ accessor.
|
||||||
@ -5394,7 +5396,7 @@ class Map: public HeapObject {
|
|||||||
inline void set_is_observed();
|
inline void set_is_observed();
|
||||||
inline bool is_observed();
|
inline bool is_observed();
|
||||||
|
|
||||||
// Tells whether the instance has a [[Call]] internal field.
|
// Tells whether the instance has a [[Call]] internal method.
|
||||||
// This property is implemented according to ES6, section 7.2.3.
|
// This property is implemented according to ES6, section 7.2.3.
|
||||||
inline void set_is_callable();
|
inline void set_is_callable();
|
||||||
inline bool is_callable() const;
|
inline bool is_callable() const;
|
||||||
@ -5723,6 +5725,7 @@ class Map: public HeapObject {
|
|||||||
inline bool IsPrimitiveMap();
|
inline bool IsPrimitiveMap();
|
||||||
inline bool IsJSObjectMap();
|
inline bool IsJSObjectMap();
|
||||||
inline bool IsJSArrayMap();
|
inline bool IsJSArrayMap();
|
||||||
|
inline bool IsJSFunctionMap();
|
||||||
inline bool IsStringMap();
|
inline bool IsStringMap();
|
||||||
inline bool IsJSProxyMap();
|
inline bool IsJSProxyMap();
|
||||||
inline bool IsJSGlobalProxyMap();
|
inline bool IsJSGlobalProxyMap();
|
||||||
@ -5827,7 +5830,7 @@ class Map: public HeapObject {
|
|||||||
static const int kIsUndetectable = 4;
|
static const int kIsUndetectable = 4;
|
||||||
static const int kIsObserved = 5;
|
static const int kIsObserved = 5;
|
||||||
static const int kIsAccessCheckNeeded = 6;
|
static const int kIsAccessCheckNeeded = 6;
|
||||||
class FunctionWithPrototype: public BitField<bool, 7, 1> {};
|
static const int kIsConstructor = 7;
|
||||||
|
|
||||||
// Bit positions for bit field 2
|
// Bit positions for bit field 2
|
||||||
static const int kIsExtensible = 0;
|
static const int kIsExtensible = 0;
|
||||||
@ -7142,7 +7145,6 @@ class JSFunction: public JSObject {
|
|||||||
// After prototype is removed, it will not be created when accessed, and
|
// After prototype is removed, it will not be created when accessed, and
|
||||||
// [[Construct]] from this function will not be allowed.
|
// [[Construct]] from this function will not be allowed.
|
||||||
bool RemovePrototype();
|
bool RemovePrototype();
|
||||||
inline bool should_have_prototype();
|
|
||||||
|
|
||||||
// Accessor for this function's initial map's [[class]]
|
// Accessor for this function's initial map's [[class]]
|
||||||
// property. This is primarily used by ECMA native functions. This
|
// property. This is primarily used by ECMA native functions. This
|
||||||
|
@ -1280,9 +1280,8 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
|
|||||||
Scanner::Location old_super_loc = function_state_->super_location();
|
Scanner::Location old_super_loc = function_state_->super_location();
|
||||||
Statement* stat = ParseStatementListItem(CHECK_OK);
|
Statement* stat = ParseStatementListItem(CHECK_OK);
|
||||||
|
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) && scope_->is_function_scope() &&
|
||||||
scope_->is_function_scope() &&
|
IsClassConstructor(function_state_->kind())) {
|
||||||
i::IsConstructor(function_state_->kind())) {
|
|
||||||
Scanner::Location this_loc = function_state_->this_location();
|
Scanner::Location this_loc = function_state_->this_location();
|
||||||
Scanner::Location super_loc = function_state_->super_location();
|
Scanner::Location super_loc = function_state_->super_location();
|
||||||
if (this_loc.beg_pos != old_this_loc.beg_pos &&
|
if (this_loc.beg_pos != old_this_loc.beg_pos &&
|
||||||
@ -1336,7 +1335,7 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
|
|||||||
if (use_strong_found) {
|
if (use_strong_found) {
|
||||||
scope_->SetLanguageMode(
|
scope_->SetLanguageMode(
|
||||||
static_cast<LanguageMode>(scope_->language_mode() | STRONG));
|
static_cast<LanguageMode>(scope_->language_mode() | STRONG));
|
||||||
if (i::IsConstructor(function_state_->kind())) {
|
if (IsClassConstructor(function_state_->kind())) {
|
||||||
// "use strong" cannot occur in a class constructor body, to avoid
|
// "use strong" cannot occur in a class constructor body, to avoid
|
||||||
// unintuitive strong class object semantics.
|
// unintuitive strong class object semantics.
|
||||||
ParserTraits::ReportMessageAt(
|
ParserTraits::ReportMessageAt(
|
||||||
@ -2642,7 +2641,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
|
|||||||
// Fall through.
|
// Fall through.
|
||||||
case Token::SUPER:
|
case Token::SUPER:
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) &&
|
||||||
i::IsConstructor(function_state_->kind())) {
|
IsClassConstructor(function_state_->kind())) {
|
||||||
bool is_this = peek() == Token::THIS;
|
bool is_this = peek() == Token::THIS;
|
||||||
Expression* expr;
|
Expression* expr;
|
||||||
ExpressionClassifier classifier;
|
ExpressionClassifier classifier;
|
||||||
@ -2849,7 +2848,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) &&
|
||||||
i::IsConstructor(function_state_->kind())) {
|
IsClassConstructor(function_state_->kind())) {
|
||||||
int pos = peek_position();
|
int pos = peek_position();
|
||||||
ReportMessageAt(Scanner::Location(pos, pos + 1),
|
ReportMessageAt(Scanner::Location(pos, pos + 1),
|
||||||
MessageTemplate::kStrongConstructorReturnValue);
|
MessageTemplate::kStrongConstructorReturnValue);
|
||||||
@ -4604,7 +4603,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
|||||||
|
|
||||||
// For concise constructors, check that they are constructed,
|
// For concise constructors, check that they are constructed,
|
||||||
// not called.
|
// not called.
|
||||||
if (i::IsConstructor(kind)) {
|
if (IsClassConstructor(kind)) {
|
||||||
AddAssertIsConstruct(result, pos);
|
AddAssertIsConstruct(result, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +232,8 @@ void PreParser::ParseStatementList(int end_token, bool* ok,
|
|||||||
Statement statement = ParseStatementListItem(ok);
|
Statement statement = ParseStatementListItem(ok);
|
||||||
if (!*ok) return;
|
if (!*ok) return;
|
||||||
|
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) && scope_->is_function_scope() &&
|
||||||
scope_->is_function_scope() &&
|
IsClassConstructor(function_state_->kind())) {
|
||||||
i::IsConstructor(function_state_->kind())) {
|
|
||||||
Scanner::Location this_loc = function_state_->this_location();
|
Scanner::Location this_loc = function_state_->this_location();
|
||||||
Scanner::Location super_loc = function_state_->super_location();
|
Scanner::Location super_loc = function_state_->super_location();
|
||||||
if (this_loc.beg_pos != old_this_loc.beg_pos &&
|
if (this_loc.beg_pos != old_this_loc.beg_pos &&
|
||||||
@ -262,7 +261,7 @@ void PreParser::ParseStatementList(int end_token, bool* ok,
|
|||||||
} else if (use_strong_found) {
|
} else if (use_strong_found) {
|
||||||
scope_->SetLanguageMode(static_cast<LanguageMode>(
|
scope_->SetLanguageMode(static_cast<LanguageMode>(
|
||||||
scope_->language_mode() | STRONG));
|
scope_->language_mode() | STRONG));
|
||||||
if (i::IsConstructor(function_state_->kind())) {
|
if (IsClassConstructor(function_state_->kind())) {
|
||||||
// "use strong" cannot occur in a class constructor body, to avoid
|
// "use strong" cannot occur in a class constructor body, to avoid
|
||||||
// unintuitive strong class object semantics.
|
// unintuitive strong class object semantics.
|
||||||
PreParserTraits::ReportMessageAt(
|
PreParserTraits::ReportMessageAt(
|
||||||
@ -639,7 +638,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
|
|||||||
// Fall through.
|
// Fall through.
|
||||||
case Token::SUPER:
|
case Token::SUPER:
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) &&
|
||||||
i::IsConstructor(function_state_->kind())) {
|
IsClassConstructor(function_state_->kind())) {
|
||||||
bool is_this = peek() == Token::THIS;
|
bool is_this = peek() == Token::THIS;
|
||||||
Expression expr = Expression::Default();
|
Expression expr = Expression::Default();
|
||||||
ExpressionClassifier classifier;
|
ExpressionClassifier classifier;
|
||||||
@ -790,7 +789,7 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
|
|||||||
tok != Token::RBRACE &&
|
tok != Token::RBRACE &&
|
||||||
tok != Token::EOS) {
|
tok != Token::EOS) {
|
||||||
if (is_strong(language_mode()) &&
|
if (is_strong(language_mode()) &&
|
||||||
i::IsConstructor(function_state_->kind())) {
|
IsClassConstructor(function_state_->kind())) {
|
||||||
int pos = peek_position();
|
int pos = peek_position();
|
||||||
ReportMessageAt(Scanner::Location(pos, pos + 1),
|
ReportMessageAt(Scanner::Location(pos, pos + 1),
|
||||||
MessageTemplate::kStrongConstructorReturnValue);
|
MessageTemplate::kStrongConstructorReturnValue);
|
||||||
|
@ -2228,7 +2228,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|||||||
if (FLAG_strong_this && is_strong(language_mode())) {
|
if (FLAG_strong_this && is_strong(language_mode())) {
|
||||||
// Constructors' usages of 'this' in strong mode are parsed separately.
|
// Constructors' usages of 'this' in strong mode are parsed separately.
|
||||||
// TODO(rossberg): this does not work with arrow functions yet.
|
// TODO(rossberg): this does not work with arrow functions yet.
|
||||||
if (i::IsConstructor(function_state_->kind())) {
|
if (IsClassConstructor(function_state_->kind())) {
|
||||||
ReportMessage(MessageTemplate::kStrongConstructorThis);
|
ReportMessage(MessageTemplate::kStrongConstructorThis);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
break;
|
break;
|
||||||
@ -3612,7 +3612,7 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new,
|
|||||||
Scope* scope = scope_->ReceiverScope();
|
Scope* scope = scope_->ReceiverScope();
|
||||||
FunctionKind kind = scope->function_kind();
|
FunctionKind kind = scope->function_kind();
|
||||||
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
|
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
|
||||||
i::IsConstructor(kind)) {
|
IsClassConstructor(kind)) {
|
||||||
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
|
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
|
||||||
scope->RecordSuperPropertyUsage();
|
scope->RecordSuperPropertyUsage();
|
||||||
return this->SuperPropertyReference(scope_, factory(), pos);
|
return this->SuperPropertyReference(scope_, factory(), pos);
|
||||||
|
@ -105,8 +105,9 @@ static MaybeHandle<Object> DefineClass(Isolate* isolate, Handle<Object> name,
|
|||||||
} else {
|
} else {
|
||||||
if (super_class->IsNull()) {
|
if (super_class->IsNull()) {
|
||||||
prototype_parent = isolate->factory()->null_value();
|
prototype_parent = isolate->factory()->null_value();
|
||||||
} else if (super_class->IsJSFunction()) { // TODO(bmeurer): IsConstructor.
|
} else if (super_class->IsConstructor()) {
|
||||||
if (Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
|
if (super_class->IsJSFunction() &&
|
||||||
|
Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
|
||||||
THROW_NEW_ERROR(
|
THROW_NEW_ERROR(
|
||||||
isolate,
|
isolate,
|
||||||
NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class),
|
NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class),
|
||||||
|
@ -159,7 +159,7 @@ RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
|
|||||||
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
||||||
RUNTIME_ASSERT(fun->should_have_prototype());
|
RUNTIME_ASSERT(fun->IsConstructor());
|
||||||
RETURN_FAILURE_ON_EXCEPTION(isolate,
|
RETURN_FAILURE_ON_EXCEPTION(isolate,
|
||||||
Accessors::FunctionSetPrototype(fun, value));
|
Accessors::FunctionSetPrototype(fun, value));
|
||||||
return args[0]; // return TOS
|
return args[0]; // return TOS
|
||||||
@ -270,30 +270,10 @@ RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
|
|||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_IsConstructor) {
|
RUNTIME_FUNCTION(Runtime_IsConstructor) {
|
||||||
HandleScope handles(isolate);
|
SealHandleScope shs(isolate);
|
||||||
RUNTIME_ASSERT(args.length() == 1);
|
DCHECK_EQ(1, args.length());
|
||||||
|
CONVERT_ARG_CHECKED(Object, object, 0);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
return isolate->heap()->ToBoolean(object->IsConstructor());
|
||||||
|
|
||||||
// TODO(caitp): implement this in a better/simpler way, allow inlining via TF
|
|
||||||
if (object->IsJSFunction()) {
|
|
||||||
Handle<JSFunction> func = Handle<JSFunction>::cast(object);
|
|
||||||
bool should_have_prototype = func->should_have_prototype();
|
|
||||||
if (func->shared()->bound()) {
|
|
||||||
Handle<FixedArray> bound_args =
|
|
||||||
Handle<FixedArray>(FixedArray::cast(func->function_bindings()));
|
|
||||||
Handle<Object> bound_function(
|
|
||||||
JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
|
|
||||||
isolate);
|
|
||||||
if (bound_function->IsJSFunction()) {
|
|
||||||
Handle<JSFunction> bound = Handle<JSFunction>::cast(bound_function);
|
|
||||||
DCHECK(!bound->shared()->bound());
|
|
||||||
should_have_prototype = bound->should_have_prototype();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isolate->heap()->ToBoolean(should_have_prototype);
|
|
||||||
}
|
|
||||||
return isolate->heap()->false_value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -437,6 +417,10 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
|
|||||||
bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
|
bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
|
||||||
REGULAR_PROTOTYPE);
|
REGULAR_PROTOTYPE);
|
||||||
}
|
}
|
||||||
|
if (bound_function_map->is_constructor() != bindee->IsConstructor()) {
|
||||||
|
bound_function_map = Map::Copy(bound_function_map, "IsConstructor");
|
||||||
|
bound_function_map->set_is_constructor(bindee->IsConstructor());
|
||||||
|
}
|
||||||
JSObject::MigrateToMap(bound_function, bound_function_map);
|
JSObject::MigrateToMap(bound_function, bound_function_map);
|
||||||
|
|
||||||
Handle<String> length_string = isolate->factory()->length_string();
|
Handle<String> length_string = isolate->factory()->length_string();
|
||||||
|
@ -1056,9 +1056,8 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
|||||||
Handle<JSFunction>::cast(original_constructor);
|
Handle<JSFunction>::cast(original_constructor);
|
||||||
|
|
||||||
|
|
||||||
// If function should not have prototype, construction is not allowed. In this
|
// Check that function is a constructor.
|
||||||
// case generated code bailouts here, since function has no initial_map.
|
if (!function->IsConstructor()) {
|
||||||
if (!function->should_have_prototype() && !function->shared()->bound()) {
|
|
||||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
isolate, NewTypeError(MessageTemplate::kNotConstructor, constructor));
|
isolate, NewTypeError(MessageTemplate::kNotConstructor, constructor));
|
||||||
}
|
}
|
||||||
|
@ -357,7 +357,7 @@ void Scope::Initialize() {
|
|||||||
Variable::NORMAL, kCreatedInitialized);
|
Variable::NORMAL, kCreatedInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConciseMethod(function_kind_) || IsConstructor(function_kind_) ||
|
if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
|
||||||
IsAccessorFunction(function_kind_)) {
|
IsAccessorFunction(function_kind_)) {
|
||||||
variables_.Declare(this, ast_value_factory_->this_function_string(),
|
variables_.Declare(this, ast_value_factory_->this_function_string(),
|
||||||
CONST, Variable::NORMAL, kCreatedInitialized);
|
CONST, Variable::NORMAL, kCreatedInitialized);
|
||||||
@ -1285,7 +1285,7 @@ ClassVariable* Scope::ClassVariableForMethod() const {
|
|||||||
// It needs to be investigated whether this causes any practical problems.
|
// It needs to be investigated whether this causes any practical problems.
|
||||||
if (!is_function_scope()) return nullptr;
|
if (!is_function_scope()) return nullptr;
|
||||||
if (IsInObjectLiteral(function_kind_)) return nullptr;
|
if (IsInObjectLiteral(function_kind_)) return nullptr;
|
||||||
if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) &&
|
if (!IsConciseMethod(function_kind_) && !IsClassConstructor(function_kind_) &&
|
||||||
!IsAccessorFunction(function_kind_)) {
|
!IsAccessorFunction(function_kind_)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ class Scope: public ZoneObject {
|
|||||||
return scope_uses_super_property_ ||
|
return scope_uses_super_property_ ||
|
||||||
(scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
|
(scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
|
||||||
IsAccessorFunction(function_kind()) ||
|
IsAccessorFunction(function_kind()) ||
|
||||||
IsConstructor(function_kind())));
|
IsClassConstructor(function_kind())));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Scope* NearestOuterEvalScope() const {
|
const Scope* NearestOuterEvalScope() const {
|
||||||
@ -445,7 +445,7 @@ class Scope: public ZoneObject {
|
|||||||
Variable* this_function_var() const {
|
Variable* this_function_var() const {
|
||||||
// This is only used in derived constructors atm.
|
// This is only used in derived constructors atm.
|
||||||
DCHECK(this_function_ == nullptr ||
|
DCHECK(this_function_ == nullptr ||
|
||||||
(is_function_scope() && (IsConstructor(function_kind()) ||
|
(is_function_scope() && (IsClassConstructor(function_kind()) ||
|
||||||
IsConciseMethod(function_kind()) ||
|
IsConciseMethod(function_kind()) ||
|
||||||
IsAccessorFunction(function_kind()))));
|
IsAccessorFunction(function_kind()))));
|
||||||
return this_function_;
|
return this_function_;
|
||||||
|
@ -1770,6 +1770,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- rax : the number of arguments (not including the receiver)
|
||||||
|
// -- rdx : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -- rdi : the constructor to call (checked to be a JSFunctionProxy)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
@ -1780,35 +1795,35 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
|||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
StackArgumentsAccessor args(rsp, rax);
|
StackArgumentsAccessor args(rsp, rax);
|
||||||
|
|
||||||
Label non_callable, non_function;
|
// Check if target has a [[Construct]] internal method.
|
||||||
__ JumpIfSmi(rdi, &non_callable);
|
Label non_constructor;
|
||||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
__ JumpIfSmi(rdi, &non_constructor, Label::kNear);
|
||||||
|
__ movp(rcx, FieldOperand(rdi, HeapObject::kMapOffset));
|
||||||
|
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
||||||
|
Immediate(1 << Map::kIsConstructor));
|
||||||
|
__ j(zero, &non_constructor, Label::kNear);
|
||||||
|
|
||||||
|
// Dispatch based on instance type.
|
||||||
|
__ CmpInstanceType(rcx, JS_FUNCTION_TYPE);
|
||||||
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
||||||
RelocInfo::CODE_TARGET);
|
RelocInfo::CODE_TARGET);
|
||||||
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
|
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
|
||||||
__ j(not_equal, &non_function, Label::kNear);
|
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
// 1. Construct of function proxy.
|
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
{
|
||||||
__ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
|
// Overwrite the original receiver with the (original) target.
|
||||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
__ movp(args.GetReceiverOperand(), rdi);
|
||||||
|
// Let the "call_as_constructor_delegate" take care of the rest.
|
||||||
|
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Construct of something else, which might have a [[Construct]] internal
|
// Called Construct on an Object that doesn't have a [[Construct]] internal
|
||||||
// method (if not we raise an exception).
|
// method.
|
||||||
__ bind(&non_function);
|
__ bind(&non_constructor);
|
||||||
// Check if target has a [[Call]] internal method.
|
|
||||||
// TODO(bmeurer): This shoud use IsConstructor once available.
|
|
||||||
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
|
||||||
Immediate(1 << Map::kIsCallable));
|
|
||||||
__ j(zero, &non_callable, Label::kNear);
|
|
||||||
// Overwrite the original receiver with the (original) target.
|
|
||||||
__ movp(args.GetReceiverOperand(), rdi);
|
|
||||||
// Let the "call_as_constructor_delegate" take care of the rest.
|
|
||||||
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
// 3. Construct of something that is not callable.
|
|
||||||
__ bind(&non_callable);
|
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ Push(rdi);
|
__ Push(rdi);
|
||||||
|
Loading…
Reference in New Issue
Block a user