From 8a378f46d52ce64578c71313ed76a67592fbf63c Mon Sep 17 00:00:00 2001 From: bmeurer Date: Wed, 2 Sep 2015 23:01:12 -0700 Subject: [PATCH] [es6] Initial steps towards a correct implementation of IsCallable. This turns the has_instance_call_handler bit on Map into an is_callable bit, that matches the spec definition of IsCallable (i.e. instances have [[Call]] internal methods). Also fix the typeof operator to properly say "function" for everything that is callable. Also remove the (unused) premature %_GetPrototype optimization from Crankshaft, which just complicated the Map bit swap. R=mstarzinger@chromium.org, rossberg@chromium.org, yangguo@chromium.org CQ_INCLUDE_TRYBOTS=tryserver.v8:v8_linux_layout_dbg Review URL: https://codereview.chromium.org/1316933002 Cr-Commit-Position: refs/heads/master@{#30552} --- src/api-natives.cc | 4 +- src/api.cc | 28 ++- src/arm/lithium-codegen-arm.cc | 26 ++- src/arm/macro-assembler-arm.cc | 15 -- src/arm/macro-assembler-arm.h | 9 - src/arm64/lithium-codegen-arm64.cc | 23 +-- src/array.js | 18 +- src/bootstrapper.cc | 17 +- src/builtins.cc | 2 +- src/code-stubs-hydrogen.cc | 20 ++- src/collection.js | 8 +- src/execution.cc | 160 ++++++++---------- src/execution.h | 20 +-- src/factory.cc | 4 +- src/factory.h | 2 +- src/full-codegen/arm/full-codegen-arm.cc | 19 +-- src/full-codegen/arm64/full-codegen-arm64.cc | 26 ++- src/full-codegen/ia32/full-codegen-ia32.cc | 22 +-- src/full-codegen/mips/full-codegen-mips.cc | 22 +-- .../mips64/full-codegen-mips64.cc | 22 +-- src/full-codegen/x64/full-codegen-x64.cc | 19 ++- src/harmony-array.js | 6 +- src/hydrogen-instructions.cc | 29 ++-- src/hydrogen-instructions.h | 4 +- src/hydrogen.cc | 47 ----- src/hydrogen.h | 1 - src/ia32/lithium-codegen-ia32.cc | 18 +- src/json.js | 6 +- src/macros.py | 5 +- src/mips/lithium-codegen-mips.cc | 28 ++- src/mips64/lithium-codegen-mips64.cc | 28 ++- src/object-observe.js | 16 +- src/objects-debug.cc | 3 + src/objects-inl.h | 22 ++- src/objects-printer.cc | 2 +- src/objects.cc | 29 ++-- src/objects.h | 23 ++- src/promise.js | 10 +- src/proxy.js | 4 +- src/runtime.js | 37 ++-- src/runtime/runtime-classes.cc | 5 +- src/runtime/runtime-function.cc | 18 +- src/runtime/runtime-internal.cc | 26 --- src/runtime/runtime-proxy.cc | 2 +- src/runtime/runtime.h | 1 - src/string.js | 4 +- src/v8natives.js | 16 +- src/weak-collection.js | 4 +- src/x64/lithium-codegen-x64.cc | 23 +-- test/cctest/test-api.cc | 8 +- 50 files changed, 406 insertions(+), 505 deletions(-) diff --git a/src/api-natives.cc b/src/api-natives.cc index 6f179b9d3..a62c231ce 100644 --- a/src/api-natives.cc +++ b/src/api-natives.cc @@ -491,9 +491,9 @@ Handle ApiNatives::CreateApiFunction( map->set_has_indexed_interceptor(); } - // Set instance call-as-function information in the map. + // Mark instance as callable in the map. if (!obj->instance_call_handler()->IsUndefined()) { - map->set_has_instance_call_handler(); + map->set_is_callable(); } // Recursively copy parent instance templates' accessors, diff --git a/src/api.cc b/src/api.cc index 2cb41a092..e42c6930d 100644 --- a/src/api.cc +++ b/src/api.cc @@ -4264,11 +4264,9 @@ MaybeLocal Object::CallAsFunction(Local context, if (self->IsJSFunction()) { fun = i::Handle::cast(self); } else { - i::Handle delegate; - has_pending_exception = !i::Execution::TryGetFunctionDelegate(isolate, self) - .ToHandle(&delegate); + has_pending_exception = + !i::Execution::GetFunctionDelegate(isolate, self).ToHandle(&fun); RETURN_ON_FAILED_EXECUTION(Value); - fun = i::Handle::cast(delegate); recv_obj = self; } Local result; @@ -4306,21 +4304,15 @@ MaybeLocal Object::CallAsConstructor(Local context, int argc, RETURN_ON_FAILED_EXECUTION(Value); RETURN_ESCAPED(result); } - i::Handle delegate; - has_pending_exception = !i::Execution::TryGetConstructorDelegate( - isolate, self).ToHandle(&delegate); + i::Handle fun; + has_pending_exception = + !i::Execution::GetConstructorDelegate(isolate, self).ToHandle(&fun); RETURN_ON_FAILED_EXECUTION(Value); - if (!delegate->IsUndefined()) { - auto fun = i::Handle::cast(delegate); - Local result; - has_pending_exception = - !ToLocal(i::Execution::Call(isolate, fun, self, argc, args), - &result); - RETURN_ON_FAILED_EXECUTION(Value); - DCHECK(!delegate->IsUndefined()); - RETURN_ESCAPED(result); - } - return MaybeLocal(); + Local result; + has_pending_exception = !ToLocal( + i::Execution::Call(isolate, fun, self, argc, args), &result); + RETURN_ON_FAILED_EXECUTION(Value); + RETURN_ESCAPED(result); } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index fb1d84a16..6e368de03 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5534,27 +5534,25 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, final_branch_condition = ne; } else if (String::Equals(type_name, factory->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - Register type_reg = scratch; __ JumpIfSmi(input, false_label); - __ CompareObjectType(input, scratch, type_reg, JS_FUNCTION_TYPE); - __ b(eq, true_label); - __ cmp(type_reg, Operand(JS_FUNCTION_PROXY_TYPE)); + __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); + __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ and_(scratch, scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + __ cmp(scratch, Operand(1 << Map::kIsCallable)); final_branch_condition = eq; } else if (String::Equals(type_name, factory->object_string())) { - Register map = scratch; __ JumpIfSmi(input, false_label); __ CompareRoot(input, Heap::kNullValueRootIndex); __ b(eq, true_label); - __ CheckObjectTypeRange(input, - map, - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, - LAST_NONCALLABLE_SPEC_OBJECT_TYPE, - false_label); - // Check for undetectable objects => false. - __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); - __ tst(scratch, Operand(1 << Map::kIsUndetectable)); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CompareObjectType(input, scratch, ip, FIRST_SPEC_OBJECT_TYPE); + __ b(lt, false_label); + // Check for callable or undetectable objects => false. + __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ tst(scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); final_branch_condition = eq; // clang-format off diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index b832607ee..3225ce35f 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -2003,21 +2003,6 @@ void MacroAssembler::CompareObjectType(Register object, } -void MacroAssembler::CheckObjectTypeRange(Register object, - Register map, - InstanceType min_type, - InstanceType max_type, - Label* false_label) { - STATIC_ASSERT(Map::kInstanceTypeOffset < 4096); - STATIC_ASSERT(LAST_TYPE < 256); - ldr(map, FieldMemOperand(object, HeapObject::kMapOffset)); - ldrb(ip, FieldMemOperand(map, Map::kInstanceTypeOffset)); - sub(ip, ip, Operand(min_type)); - cmp(ip, Operand(max_type - min_type)); - b(hi, false_label); -} - - void MacroAssembler::CompareInstanceType(Register map, Register type_reg, InstanceType type) { diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index b10d82782..702cedb57 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -867,15 +867,6 @@ class MacroAssembler: public Assembler { Register type_reg, InstanceType type); - // Compare object type for heap object. Branch to false_label if type - // is lower than min_type or greater than max_type. - // Load map into the register map. - void CheckObjectTypeRange(Register heap_object, - Register map, - InstanceType min_type, - InstanceType max_type, - Label* false_label); - // Compare instance type in a map. map contains a valid map object whose // object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index b317900a7..529352d77 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -5855,14 +5855,15 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { EmitTestAndBranch(instr, ne, scratch, 1 << Map::kIsUndetectable); } else if (String::Equals(type_name, factory->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); DCHECK(instr->temp1() != NULL); - Register type = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp1()); __ JumpIfSmi(value, false_label); - __ JumpIfObjectType(value, type, type, JS_FUNCTION_TYPE, true_label); - // HeapObject's type has been loaded into type register by JumpIfObjectType. - EmitCompareAndBranch(instr, eq, type, JS_FUNCTION_PROXY_TYPE); + __ Ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); + __ Ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ And(scratch, scratch, + (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); + EmitCompareAndBranch(instr, eq, scratch, 1 << Map::kIsCallable); } else if (String::Equals(type_name, factory->object_string())) { DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); @@ -5871,13 +5872,13 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ JumpIfSmi(value, false_label); __ JumpIfRoot(value, Heap::kNullValueRootIndex, true_label); - __ JumpIfObjectType(value, map, scratch, - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, false_label, lt); - __ CompareInstanceType(map, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ B(gt, false_label); - // Check for undetectable objects => false. + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ JumpIfObjectType(value, map, scratch, FIRST_SPEC_OBJECT_TYPE, + false_label, lt); + // Check for callable or undetectable objects => false. __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); - EmitTestAndBranch(instr, eq, scratch, 1 << Map::kIsUndetectable); + EmitTestAndBranch(instr, eq, scratch, + (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/array.js b/src/array.js index 84c766203..b413a0cff 100644 --- a/src/array.js +++ b/src/array.js @@ -387,7 +387,7 @@ function ArrayToString() { array = TO_OBJECT(this); func = array.join; } - if (!IS_SPEC_FUNCTION(func)) { + if (!IS_CALLABLE(func)) { return %_CallFunction(array, ObjectToString); } return %_CallFunction(array, func); @@ -904,7 +904,7 @@ function InnerArraySort(length, comparefn) { // In-place QuickSort algorithm. // For short (length <= 22) arrays, insertion sort is used for efficiency. - if (!IS_SPEC_FUNCTION(comparefn)) { + if (!IS_CALLABLE(comparefn)) { comparefn = function (x, y) { if (x === y) return 0; if (%_IsSmi(x) && %_IsSmi(y)) { @@ -1196,7 +1196,7 @@ function ArraySort(comparefn) { // preserving the semantics, since the calls to the receiver function can add // or delete elements from the array. function InnerArrayFilter(f, receiver, array, length) { - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -1236,7 +1236,7 @@ function ArrayFilter(f, receiver) { } function InnerArrayForEach(f, receiver, array, length) { - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -1269,7 +1269,7 @@ function ArrayForEach(f, receiver) { function InnerArraySome(f, receiver, array, length) { - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -1306,7 +1306,7 @@ function ArraySome(f, receiver) { function InnerArrayEvery(f, receiver, array, length) { - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -1340,7 +1340,7 @@ function ArrayEvery(f, receiver) { function InnerArrayMap(f, receiver, array, length) { - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -1504,7 +1504,7 @@ function ArrayLastIndexOf(element, index) { function InnerArrayReduce(callback, current, array, length, argumentsLength) { - if (!IS_SPEC_FUNCTION(callback)) { + if (!IS_CALLABLE(callback)) { throw MakeTypeError(kCalledNonCallable, callback); } @@ -1547,7 +1547,7 @@ function ArrayReduce(callback, current) { function InnerArrayReduceRight(callback, current, array, length, argumentsLength) { - if (!IS_SPEC_FUNCTION(callback)) { + if (!IS_CALLABLE(callback)) { throw MakeTypeError(kCalledNonCallable, callback); } diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 65dbaebdb..a8858b7d0 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -488,6 +488,7 @@ Handle Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) { Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetFunctionInstanceDescriptor(map, function_mode); map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode)); + map->set_is_callable(); return map; } @@ -727,6 +728,7 @@ Handle Genesis::CreateStrictFunctionMap( Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetStrictFunctionInstanceDescriptor(map, function_mode); map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode)); + map->set_is_callable(); Map::SetPrototype(map, empty_function); return map; } @@ -738,6 +740,7 @@ Handle Genesis::CreateStrongFunctionMap( SetStrongFunctionInstanceDescriptor(map); map->set_function_with_prototype(is_constructor); Map::SetPrototype(map, empty_function); + map->set_is_callable(); map->set_is_extensible(is_constructor); map->set_is_strong(); return map; @@ -1044,8 +1047,10 @@ void Genesis::InitializeGlobal(Handle global_object, Handle global(native_context()->global_object()); // Install global Function object - InstallFunction(global, "Function", JS_FUNCTION_TYPE, JSFunction::kSize, - empty_function, Builtins::kIllegal); + Handle function_function = + InstallFunction(global, "Function", JS_FUNCTION_TYPE, JSFunction::kSize, + empty_function, Builtins::kIllegal); + function_function->initial_map()->set_is_callable(); { // --- A r r a y --- Handle array_function = @@ -2242,9 +2247,11 @@ bool Genesis::InstallNatives(ContextType context_type) { static_cast(DONT_ENUM | READ_ONLY)); static const bool kUseStrictFunctionMap = true; - InstallFunction(builtins, "GeneratorFunction", JS_FUNCTION_TYPE, - JSFunction::kSize, generator_function_prototype, - Builtins::kIllegal, kUseStrictFunctionMap); + Handle generator_function_function = + InstallFunction(builtins, "GeneratorFunction", JS_FUNCTION_TYPE, + JSFunction::kSize, generator_function_prototype, + Builtins::kIllegal, kUseStrictFunctionMap); + generator_function_function->initial_map()->set_is_callable(); // Create maps for generator functions and their prototypes. Store those // maps in the native context. The "prototype" property descriptor is diff --git a/src/builtins.cc b/src/builtins.cc index 461ba84d7..f06487ddf 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -906,7 +906,7 @@ MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor( // Get the invocation callback from the function descriptor that was // used to create the called object. - DCHECK(obj->map()->has_instance_call_handler()); + DCHECK(obj->map()->is_callable()); JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor()); // TODO(ishell): turn this back to a DCHECK. CHECK(constructor->shared()->IsApiFunction()); diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 3901ef802..9f9b14e30 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -367,14 +367,16 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { { Push(Add(factory->symbol_string())); } is_symbol.Else(); { + HValue* bit_field = Add( + map, nullptr, HObjectAccess::ForMapBitField()); + HValue* bit_field_masked = AddUncasted( + Token::BIT_AND, bit_field, + Add((1 << Map::kIsCallable) | + (1 << Map::kIsUndetectable))); IfBuilder is_function(this); - HConstant* js_function = Add(JS_FUNCTION_TYPE); - HConstant* js_function_proxy = - Add(JS_FUNCTION_PROXY_TYPE); - is_function.If(instance_type, js_function, - Token::EQ); - is_function.OrIf( - instance_type, js_function_proxy, Token::EQ); + is_function.If( + bit_field_masked, Add(1 << Map::kIsCallable), + Token::EQ); is_function.Then(); { Push(Add(factory->function_string())); } is_function.Else(); @@ -390,7 +392,9 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { #undef SIMD128_BUILDER_OPEN // Is it an undetectable object? IfBuilder is_undetectable(this); - is_undetectable.If(object); + is_undetectable.If( + bit_field_masked, Add(1 << Map::kIsUndetectable), + Token::EQ); is_undetectable.Then(); { // typeof an undetectable object is 'undefined'. diff --git a/src/collection.js b/src/collection.js index ad4ad1e08..f7db8625c 100644 --- a/src/collection.js +++ b/src/collection.js @@ -134,7 +134,7 @@ function SetConstructor(iterable) { if (!IS_NULL_OR_UNDEFINED(iterable)) { var adder = this.add; - if (!IS_SPEC_FUNCTION(adder)) { + if (!IS_CALLABLE(adder)) { throw MakeTypeError(kPropertyNotFunction, 'add', this); } @@ -245,7 +245,7 @@ function SetForEach(f, receiver) { 'Set.prototype.forEach', this); } - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; @@ -299,7 +299,7 @@ function MapConstructor(iterable) { if (!IS_NULL_OR_UNDEFINED(iterable)) { var adder = this.set; - if (!IS_SPEC_FUNCTION(adder)) { + if (!IS_CALLABLE(adder)) { throw MakeTypeError(kPropertyNotFunction, 'set', this); } @@ -436,7 +436,7 @@ function MapForEach(f, receiver) { 'Map.prototype.forEach', this); } - if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); + if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); var needs_wrapper = false; if (IS_NULL(receiver)) { if (%IsSloppyModeFunction(f)) receiver = UNDEFINED; diff --git a/src/execution.cc b/src/execution.cc index 377210e11..88511aae2 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -9,6 +9,8 @@ #include "src/deoptimizer.h" #include "src/isolate-inl.h" #include "src/messages.h" +#include "src/parser.h" +#include "src/prettyprinter.h" #include "src/vm-state-inl.h" namespace v8 { @@ -160,8 +162,8 @@ MaybeHandle Execution::Call(Isolate* isolate, Handle argv[], bool convert_receiver) { if (!callable->IsJSFunction()) { - ASSIGN_RETURN_ON_EXCEPTION( - isolate, callable, TryGetFunctionDelegate(isolate, callable), Object); + ASSIGN_RETURN_ON_EXCEPTION(isolate, callable, + GetFunctionDelegate(isolate, callable), Object); } Handle func = Handle::cast(callable); @@ -232,113 +234,95 @@ MaybeHandle Execution::TryCall(Handle func, } -Handle Execution::GetFunctionDelegate(Isolate* isolate, - Handle object) { +// static +MaybeHandle Execution::GetFunctionDelegate(Isolate* isolate, + Handle object) { DCHECK(!object->IsJSFunction()); - Factory* factory = isolate->factory(); + if (object->IsHeapObject()) { + DisallowHeapAllocation no_gc; - // If you return a function from here, it will be called when an - // attempt is made to call the given object as a function. - - // If object is a function proxy, get its handler. Iterate if necessary. - Object* fun = *object; - while (fun->IsJSFunctionProxy()) { - fun = JSFunctionProxy::cast(fun)->call_trap(); - } - if (fun->IsJSFunction()) return Handle(fun, isolate); - - // Objects created through the API can have an instance-call handler - // that should be used when calling the object as a function. - if (fun->IsHeapObject() && - HeapObject::cast(fun)->map()->has_instance_call_handler()) { - return Handle( - isolate->native_context()->call_as_function_delegate()); - } - - return factory->undefined_value(); -} - - -MaybeHandle Execution::TryGetFunctionDelegate(Isolate* isolate, - Handle object) { - DCHECK(!object->IsJSFunction()); + // If object is a function proxy, get its handler. Iterate if necessary. + Object* fun = *object; + while (fun->IsJSFunctionProxy()) { + fun = JSFunctionProxy::cast(fun)->call_trap(); + } + if (fun->IsJSFunction()) { + return handle(JSFunction::cast(fun), isolate); + } - // If object is a function proxy, get its handler. Iterate if necessary. - Object* fun = *object; - while (fun->IsJSFunctionProxy()) { - fun = JSFunctionProxy::cast(fun)->call_trap(); - } - if (fun->IsJSFunction()) return Handle(fun, isolate); - - // Objects created through the API can have an instance-call handler - // that should be used when calling the object as a function. - if (fun->IsHeapObject() && - HeapObject::cast(fun)->map()->has_instance_call_handler()) { - return Handle( - isolate->native_context()->call_as_function_delegate()); + // We can also have exotic objects with [[Call]] internal methods. + if (fun->IsCallable()) { + return handle(isolate->native_context()->call_as_function_delegate(), + isolate); + } } // If the Object doesn't have an instance-call handler we should // throw a non-callable exception. + Handle callsite = RenderCallSite(isolate, object); THROW_NEW_ERROR(isolate, - NewTypeError(MessageTemplate::kCalledNonCallable, object), - Object); + NewTypeError(MessageTemplate::kCalledNonCallable, callsite), + JSFunction); } -Handle Execution::GetConstructorDelegate(Isolate* isolate, - Handle object) { - DCHECK(!object->IsJSFunction()); - +// static +MaybeHandle Execution::GetConstructorDelegate( + Isolate* isolate, Handle object) { // If you return a function from here, it will be called when an // attempt is made to call the given object as a constructor. - // If object is a function proxies, get its handler. Iterate if necessary. - Object* fun = *object; - while (fun->IsJSFunctionProxy()) { - fun = JSFunctionProxy::cast(fun)->call_trap(); - } - if (fun->IsJSFunction()) return Handle(fun, isolate); - - // Objects created through the API can have an instance-call handler - // that should be used when calling the object as a function. - if (fun->IsHeapObject() && - HeapObject::cast(fun)->map()->has_instance_call_handler()) { - return Handle( - isolate->native_context()->call_as_constructor_delegate()); - } - - return isolate->factory()->undefined_value(); -} - - -MaybeHandle Execution::TryGetConstructorDelegate( - Isolate* isolate, Handle object) { DCHECK(!object->IsJSFunction()); + if (object->IsHeapObject()) { + DisallowHeapAllocation no_gc; + + // If object is a function proxies, get its handler. Iterate if necessary. + Object* fun = *object; + while (fun->IsJSFunctionProxy()) { + // TODO(bmeurer): This should work based on [[Construct]]; our proxies + // are screwed. + fun = JSFunctionProxy::cast(fun)->call_trap(); + } + if (fun->IsJSFunction()) { + return handle(JSFunction::cast(fun), isolate); + } - // If you return a function from here, it will be called when an - // attempt is made to call the given object as a constructor. - - // If object is a function proxies, get its handler. Iterate if necessary. - Object* fun = *object; - while (fun->IsJSFunctionProxy()) { - fun = JSFunctionProxy::cast(fun)->call_trap(); - } - if (fun->IsJSFunction()) return Handle(fun, isolate); - - // Objects created through the API can have an instance-call handler - // that should be used when calling the object as a function. - if (fun->IsHeapObject() && - HeapObject::cast(fun)->map()->has_instance_call_handler()) { - return Handle( - isolate->native_context()->call_as_constructor_delegate()); + // We can also have exotic objects with [[Construct]] internal methods. + // TODO(bmeurer): This should use IsConstructor() as dictacted by the spec. + if (fun->IsCallable()) { + return handle(isolate->native_context()->call_as_constructor_delegate(), + isolate); + } } // If the Object doesn't have an instance-call handler we should // throw a non-callable exception. + Handle callsite = RenderCallSite(isolate, object); THROW_NEW_ERROR(isolate, - NewTypeError(MessageTemplate::kCalledNonCallable, object), - Object); + NewTypeError(MessageTemplate::kCalledNonCallable, callsite), + JSFunction); +} + + +// static +Handle Execution::RenderCallSite(Isolate* isolate, + Handle object) { + MessageLocation location; + if (isolate->ComputeLocation(&location)) { + Zone zone; + base::SmartPointer info( + location.function()->shared()->is_function() + ? new ParseInfo(&zone, location.function()) + : new ParseInfo(&zone, location.script())); + if (Parser::ParseStatic(info.get())) { + CallPrinter printer(isolate, &zone); + const char* string = printer.Print(info->literal(), location.start_pos()); + return isolate->factory()->NewStringFromAsciiChecked(string); + } else { + isolate->clear_pending_exception(); + } + } + return Object::TypeOf(isolate, object); } diff --git a/src/execution.h b/src/execution.h index d7996d190..75f7a8ebc 100644 --- a/src/execution.h +++ b/src/execution.h @@ -92,25 +92,23 @@ class Execution final : public AllStatic { MUST_USE_RESULT static MaybeHandle NewJSRegExp( Handle pattern, Handle flags); - static Handle GetFunctionFor(); static Handle GetStackTraceLine(Handle recv, Handle fun, Handle pos, Handle is_global); - // Get a function delegate (or undefined) for the given non-function - // object. Used for support calling objects as functions. - static Handle GetFunctionDelegate(Isolate* isolate, - Handle object); - MUST_USE_RESULT static MaybeHandle TryGetFunctionDelegate( - Isolate* isolate, - Handle object); + // Get a function delegate for the given non-function object. + // Used for support calling objects as functions. + MUST_USE_RESULT static MaybeHandle GetFunctionDelegate( + Isolate* isolate, Handle object); // Get a function delegate (or undefined) for the given non-function // object. Used for support calling objects as constructors. - static Handle GetConstructorDelegate(Isolate* isolate, - Handle object); - static MaybeHandle TryGetConstructorDelegate(Isolate* isolate, + MUST_USE_RESULT static MaybeHandle GetConstructorDelegate( + Isolate* isolate, Handle object); + + private: + MUST_USE_RESULT static Handle RenderCallSite(Isolate* isolate, Handle object); }; diff --git a/src/factory.cc b/src/factory.cc index e934f1805..9045289bc 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1899,7 +1899,7 @@ Handle Factory::NewJSProxy(Handle handler, Handle Factory::NewJSFunctionProxy(Handle handler, - Handle call_trap, + Handle call_trap, Handle construct_trap, Handle prototype) { // Allocate map. @@ -1907,6 +1907,7 @@ Handle Factory::NewJSFunctionProxy(Handle handler, // maps. Will probably depend on the identity of the handler object, too. Handle map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize); Map::SetPrototype(map, prototype); + map->set_is_callable(); // Allocate the proxy object. Handle result = New(map, NEW_SPACE); @@ -1969,6 +1970,7 @@ void Factory::ReinitializeJSProxy(Handle proxy, InstanceType type, // Functions require some minimal initialization. if (type == JS_FUNCTION_TYPE) { map->set_function_with_prototype(true); + map->set_is_callable(); Handle js_function = Handle::cast(proxy); InitializeFunction(js_function, shared.ToHandleChecked(), context); } else { diff --git a/src/factory.h b/src/factory.h index 375c0bd3b..2596ae39c 100644 --- a/src/factory.h +++ b/src/factory.h @@ -480,7 +480,7 @@ class Factory final { // Allocates a Harmony function proxy. Handle NewJSFunctionProxy(Handle handler, - Handle call_trap, + Handle call_trap, Handle construct_trap, Handle prototype); diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index 7b52e3eca..bd361080b 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -4968,23 +4968,22 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(r0, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE); - __ b(eq, if_true); - __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE)); + __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); + __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); + __ and_(r1, r1, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + __ cmp(r1, Operand(1 << Map::kIsCallable)); Split(eq, if_true, if_false, fall_through); } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(r0, if_false); __ CompareRoot(r0, Heap::kNullValueRootIndex); __ b(eq, if_true); - // Check for JS objects => true. - __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE); __ b(lt, if_false); - __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ b(gt, if_false); - // Check for undetectable objects => false. + // Check for callable or undetectable objects => false. __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); - __ tst(r1, Operand(1 << Map::kIsUndetectable)); + __ tst(r1, Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); Split(eq, if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 1e01b0d77..65ceb7cdb 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -4668,25 +4668,21 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } else if (String::Equals(check, factory->function_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof function_string"); __ JumpIfSmi(x0, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ JumpIfObjectType(x0, x10, x11, JS_FUNCTION_TYPE, if_true); - __ CompareAndSplit(x11, JS_FUNCTION_PROXY_TYPE, eq, if_true, if_false, - fall_through); + __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); + __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); + __ And(x1, x1, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); + __ CompareAndSplit(x1, Operand(1 << Map::kIsCallable), eq, if_true, + if_false, fall_through); } else if (String::Equals(check, factory->object_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof object_string"); __ JumpIfSmi(x0, if_false); __ JumpIfRoot(x0, Heap::kNullValueRootIndex, if_true); - // Check for JS objects => true. - Register map = x10; - __ JumpIfObjectType(x0, map, x11, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, - if_false, lt); - __ CompareInstanceType(map, x11, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ B(gt, if_false); - // Check for undetectable objects => false. - __ Ldrb(x10, FieldMemOperand(map, Map::kBitFieldOffset)); - - __ TestAndSplit(x10, 1 << Map::kIsUndetectable, if_true, if_false, - fall_through); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ JumpIfObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE, if_false, lt); + // Check for callable or undetectable objects => false. + __ Ldrb(x10, FieldMemOperand(x10, Map::kBitFieldOffset)); + __ TestAndSplit(x10, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable), + if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ } else if (String::Equals(check, factory->type##_string())) { \ diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 2272e73f8..fab491b61 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -4904,27 +4904,27 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(eax, if_false); // Check for undetectable objects => true. __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); - __ test(ecx, Immediate(1 << Map::kIsUndetectable)); + __ test_b(FieldOperand(edx, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); Split(not_zero, if_true, if_false, fall_through); } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(eax, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); - __ j(equal, if_true); - __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); + // Check for callable and not undetectable objects => true. + __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); + __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); + __ and_(ecx, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); + __ cmp(ecx, 1 << Map::kIsCallable); Split(equal, if_true, if_false, fall_through); } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(eax, if_false); __ cmp(eax, isolate()->factory()->null_value()); __ j(equal, if_true); - __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, edx); __ j(below, if_false); - __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ j(above, if_false); - // Check for undetectable objects => false. + // Check for callable or undetectable objects => false. __ test_b(FieldOperand(edx, Map::kBitFieldOffset), - 1 << Map::kIsUndetectable); + (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); Split(zero, if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index cdfd78547..a2e7cbaa8 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -4997,23 +4997,23 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(v0, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ GetObjectType(v0, v0, a1); - __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE)); - Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE), - if_true, if_false, fall_through); + __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); + __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); + __ And(a1, a1, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + Split(eq, a1, Operand(1 << Map::kIsCallable), if_true, if_false, + fall_through); } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(v0, if_false); __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); - // Check for JS objects => true. + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); __ GetObjectType(v0, v0, a1); - __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); - __ Branch(if_false, gt, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - // Check for undetectable objects => false. + __ Branch(if_false, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); + // Check for callable or undetectable objects => false. __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); - __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); + __ And(a1, a1, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index 26921d640..bcd90de71 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -5000,23 +5000,23 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(v0, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ GetObjectType(v0, v0, a1); - __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE)); - Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE), - if_true, if_false, fall_through); + __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); + __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); + __ And(a1, a1, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + Split(eq, a1, Operand(1 << Map::kIsCallable), if_true, if_false, + fall_through); } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(v0, if_false); __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); - // Check for JS objects => true. + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); __ GetObjectType(v0, v0, a1); - __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); - __ Branch(if_false, gt, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - // Check for undetectable objects => false. + __ Branch(if_false, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); + // Check for callable or undetectable objects => false. __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); - __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); + __ And(a1, a1, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 2d64a6629..a91ccdd02 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -4918,22 +4918,23 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, Split(not_zero, if_true, if_false, fall_through); } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(rax, if_false); - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); - __ j(equal, if_true); - __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE); + // Check for callable and not undetectable objects => true. + __ movp(rdx, FieldOperand(rax, HeapObject::kMapOffset)); + __ movzxbl(rdx, FieldOperand(rdx, Map::kBitFieldOffset)); + __ andb(rdx, + Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + __ cmpb(rdx, Immediate(1 << Map::kIsCallable)); Split(equal, if_true, if_false, fall_through); } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(rax, if_false); __ CompareRoot(rax, Heap::kNullValueRootIndex); __ j(equal, if_true); - __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rdx); __ j(below, if_false); - __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ j(above, if_false); - // Check for undetectable objects => false. + // Check for callable or undetectable objects => false. __ testb(FieldOperand(rdx, Map::kBitFieldOffset), - Immediate(1 << Map::kIsUndetectable)); + Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); Split(zero, if_true, if_false, fall_through); // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ diff --git a/src/harmony-array.js b/src/harmony-array.js index 885950b8e..779b67a80 100644 --- a/src/harmony-array.js +++ b/src/harmony-array.js @@ -91,7 +91,7 @@ function ArrayCopyWithin(target, start, end) { } function InnerArrayFind(predicate, thisArg, array, length) { - if (!IS_SPEC_FUNCTION(predicate)) { + if (!IS_CALLABLE(predicate)) { throw MakeTypeError(kCalledNonCallable, predicate); } @@ -124,7 +124,7 @@ function ArrayFind(predicate, thisArg) { } function InnerArrayFindIndex(predicate, thisArg, array, length) { - if (!IS_SPEC_FUNCTION(predicate)) { + if (!IS_CALLABLE(predicate)) { throw MakeTypeError(kCalledNonCallable, predicate); } @@ -210,7 +210,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) { var mapping = !IS_UNDEFINED(mapfn); if (mapping) { - if (!IS_SPEC_FUNCTION(mapfn)) { + if (!IS_CALLABLE(mapfn)) { throw MakeTypeError(kCalledNonCallable, mapfn); } else if (%IsSloppyModeFunction(mapfn)) { if (IS_NULL(receiver)) { diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 7dd604b5f..be0b71be4 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1299,7 +1299,9 @@ std::ostream& HTypeofIsAndBranch::PrintDataTo( } -static String* TypeOfString(HConstant* constant, Isolate* isolate) { +namespace { + +String* TypeOfString(HConstant* constant, Isolate* isolate) { Heap* heap = isolate->heap(); if (constant->HasNumberValue()) return heap->number_string(); if (constant->IsUndetectable()) return heap->undefined_string(); @@ -1330,14 +1332,14 @@ static String* TypeOfString(HConstant* constant, Isolate* isolate) { UNREACHABLE(); return nullptr; } - case JS_FUNCTION_TYPE: - case JS_FUNCTION_PROXY_TYPE: - return heap->function_string(); default: + if (constant->IsCallable()) return heap->function_string(); return heap->object_string(); } } +} // namespace + bool HTypeofIsAndBranch::KnownSuccessorBlock(HBasicBlock** block) { if (FLAG_fold_constants && value()->IsConstant()) { @@ -2705,15 +2707,15 @@ HConstant::HConstant(Handle object, Representation r) : HTemplateInstruction<0>(HType::FromValue(object)), object_(Unique::CreateUninitialized(object)), object_map_(Handle::null()), - bit_field_(HasStableMapValueField::encode(false) | - HasSmiValueField::encode(false) | - HasInt32ValueField::encode(false) | - HasDoubleValueField::encode(false) | - HasExternalReferenceValueField::encode(false) | - IsNotInNewSpaceField::encode(true) | - BooleanValueField::encode(object->BooleanValue()) | - IsUndetectableField::encode(false) | - InstanceTypeField::encode(kUnknownInstanceType)) { + bit_field_( + HasStableMapValueField::encode(false) | + HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) | + HasDoubleValueField::encode(false) | + HasExternalReferenceValueField::encode(false) | + IsNotInNewSpaceField::encode(true) | + BooleanValueField::encode(object->BooleanValue()) | + IsUndetectableField::encode(false) | IsCallableField::encode(false) | + InstanceTypeField::encode(kUnknownInstanceType)) { if (object->IsHeapObject()) { Handle heap_object = Handle::cast(object); Isolate* isolate = heap_object->GetIsolate(); @@ -2723,6 +2725,7 @@ HConstant::HConstant(Handle object, Representation r) bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type()); bit_field_ = IsUndetectableField::update(bit_field_, map->is_undetectable()); + bit_field_ = IsCallableField::update(bit_field_, map->is_callable()); if (map->is_stable()) object_map_ = Unique::CreateImmovable(map); bit_field_ = HasStableMapValueField::update( bit_field_, diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 70b785475..e1bca999e 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -3623,6 +3623,7 @@ class HConstant final : public HTemplateInstruction<0> { bool HasBooleanValue() const { return type_.IsBoolean(); } bool BooleanValue() const { return BooleanValueField::decode(bit_field_); } + bool IsCallable() const { return IsCallableField::decode(bit_field_); } bool IsUndetectable() const { return IsUndetectableField::decode(bit_field_); } @@ -3755,9 +3756,10 @@ class HConstant final : public HTemplateInstruction<0> { class IsNotInNewSpaceField : public BitField {}; class BooleanValueField : public BitField {}; class IsUndetectableField : public BitField {}; + class IsCallableField : public BitField {}; static const InstanceType kUnknownInstanceType = FILLER_TYPE; - class InstanceTypeField : public BitField {}; + class InstanceTypeField : public BitField {}; // If this is a numerical constant, object_ either points to the // HeapObject the constant originated from or is null. If the diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 6effe1c39..46a1e6f53 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -12771,53 +12771,6 @@ void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) { } -void HOptimizedGraphBuilder::GenerateGetPrototype(CallRuntime* call) { - DCHECK(call->arguments()->length() == 1); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); - HValue* object = Pop(); - - NoObservableSideEffectsScope no_effects(this); - - HValue* map = Add(object, nullptr, HObjectAccess::ForMap()); - HValue* bit_field = - Add(map, nullptr, HObjectAccess::ForMapBitField()); - HValue* is_access_check_needed_mask = - Add(1 << Map::kIsAccessCheckNeeded); - HValue* is_access_check_needed_test = AddUncasted( - Token::BIT_AND, bit_field, is_access_check_needed_mask); - - HValue* proto = - Add(map, nullptr, HObjectAccess::ForPrototype()); - HValue* proto_map = - Add(proto, nullptr, HObjectAccess::ForMap()); - HValue* proto_bit_field = - Add(proto_map, nullptr, HObjectAccess::ForMapBitField()); - HValue* is_hidden_prototype_mask = - Add(1 << Map::kIsHiddenPrototype); - HValue* is_hidden_prototype_test = AddUncasted( - Token::BIT_AND, proto_bit_field, is_hidden_prototype_mask); - - { - IfBuilder needs_runtime(this); - needs_runtime.If( - is_access_check_needed_test, graph()->GetConstant0(), Token::NE); - needs_runtime.OrIf( - is_hidden_prototype_test, graph()->GetConstant0(), Token::NE); - - needs_runtime.Then(); - { - Add(object); - Push( - Add(Runtime::FunctionForId(Runtime::kGetPrototype), 1)); - } - - needs_runtime.Else(); - Push(proto); - } - return ast_context()->ReturnValue(Pop()); -} - - #undef CHECK_BAILOUT #undef CHECK_ALIVE diff --git a/src/hydrogen.h b/src/hydrogen.h index c5f35a32b..0a6b2e295 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2269,7 +2269,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { F(TheHole) \ /* Arrays */ \ F(HasFastPackedElements) \ - F(GetPrototype) \ /* Strings */ \ F(StringGetLength) \ /* JSValue */ \ diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index e8cf3452b..7f44b9e77 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5425,24 +5425,24 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { final_branch_condition = not_zero; } else if (String::Equals(type_name, factory()->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label, false_distance); - __ CmpObjectType(input, JS_FUNCTION_TYPE, input); - __ j(equal, true_label, true_distance); - __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); + // Check for callable and not undetectable objects => true. + __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); + __ movzx_b(input, FieldOperand(input, Map::kBitFieldOffset)); + __ and_(input, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); + __ cmp(input, 1 << Map::kIsCallable); final_branch_condition = equal; } else if (String::Equals(type_name, factory()->object_string())) { __ JumpIfSmi(input, false_label, false_distance); __ cmp(input, factory()->null_value()); __ j(equal, true_label, true_distance); - __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, input); __ j(below, false_label, false_distance); - __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ j(above, false_label, false_distance); - // Check for undetectable objects => false. + // Check for callable or undetectable objects => false. __ test_b(FieldOperand(input, Map::kBitFieldOffset), - 1 << Map::kIsUndetectable); + (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); final_branch_condition = zero; // clang-format off diff --git a/src/json.js b/src/json.js index 7ada63eb5..5ddf869ae 100644 --- a/src/json.js +++ b/src/json.js @@ -58,7 +58,7 @@ function Revive(holder, name, reviver) { function JSONParse(text, reviver) { var unfiltered = %ParseJson(TO_STRING_INLINE(text)); - if (IS_SPEC_FUNCTION(reviver)) { + if (IS_CALLABLE(reviver)) { return Revive({'': unfiltered}, '', reviver); } else { return unfiltered; @@ -146,11 +146,11 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) { var value = holder[key]; if (IS_SPEC_OBJECT(value)) { var toJSON = value.toJSON; - if (IS_SPEC_FUNCTION(toJSON)) { + if (IS_CALLABLE(toJSON)) { value = %_CallFunction(value, key, toJSON); } } - if (IS_SPEC_FUNCTION(replacer)) { + if (IS_CALLABLE(replacer)) { value = %_CallFunction(holder, key, value, replacer); } if (IS_STRING(value)) { diff --git a/src/macros.py b/src/macros.py index 63b0b2948..baaea933a 100644 --- a/src/macros.py +++ b/src/macros.py @@ -128,10 +128,7 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg)); # Macro for ECMAScript 5 queries of the type: # "IsCallable(O)" -# We assume here that this is the same as being either a function or a function -# proxy. That ignores host objects with [[Call]] methods, but in most situations -# we cannot handle those anyway. -macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function'); +macro IS_CALLABLE(arg) = (typeof(arg) === 'function'); # Macro for ES6 CheckObjectCoercible # Will throw a TypeError of the form "[functionName] called on null or undefined". diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 01ccdf721..5586ed1ab 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5581,28 +5581,26 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, final_branch_condition = ne; } else if (String::Equals(type_name, factory->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label); - __ GetObjectType(input, scratch, input); - __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE)); - *cmp1 = input; - *cmp2 = Operand(JS_FUNCTION_PROXY_TYPE); + __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); + __ lbu(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ And(scratch, scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + *cmp1 = scratch; + *cmp2 = Operand(1 << Map::kIsCallable); final_branch_condition = eq; } else if (String::Equals(type_name, factory->object_string())) { __ JumpIfSmi(input, false_label); __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); - Register map = input; - __ GetObjectType(input, map, scratch); - __ Branch(false_label, - lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ Branch(USE_DELAY_SLOT, false_label, - gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - // map is still valid, so the BitField can be loaded in delay slot. - // Check for undetectable objects => false. - __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); - __ And(at, at, 1 << Map::kIsUndetectable); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ GetObjectType(input, scratch, scratch1()); + __ Branch(false_label, lt, scratch1(), Operand(FIRST_SPEC_OBJECT_TYPE)); + // Check for callable or undetectable objects => false. + __ lbu(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ And(at, scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); *cmp1 = at; *cmp2 = Operand(zero_reg); final_branch_condition = eq; diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index 8168d7041..a612681c5 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -5768,28 +5768,26 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, final_branch_condition = ne; } else if (String::Equals(type_name, factory->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label); - __ GetObjectType(input, scratch, input); - __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE)); - *cmp1 = input; - *cmp2 = Operand(JS_FUNCTION_PROXY_TYPE); + __ ld(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); + __ lbu(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ And(scratch, scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + *cmp1 = scratch; + *cmp2 = Operand(1 << Map::kIsCallable); final_branch_condition = eq; } else if (String::Equals(type_name, factory->object_string())) { __ JumpIfSmi(input, false_label); __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); - Register map = input; - __ GetObjectType(input, map, scratch); - __ Branch(false_label, - lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ Branch(USE_DELAY_SLOT, false_label, - gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - // map is still valid, so the BitField can be loaded in delay slot. - // Check for undetectable objects => false. - __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); - __ And(at, at, 1 << Map::kIsUndetectable); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ GetObjectType(input, scratch, scratch1()); + __ Branch(false_label, lt, scratch1(), Operand(FIRST_SPEC_OBJECT_TYPE)); + // Check for callable or undetectable objects => false. + __ lbu(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); + __ And(at, scratch, + Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); *cmp1 = at; *cmp2 = Operand(zero_reg); final_branch_condition = eq; diff --git a/src/object-observe.js b/src/object-observe.js index 0f1f6d37f..be4c24e21 100644 --- a/src/object-observe.js +++ b/src/object-observe.js @@ -178,12 +178,12 @@ function ObserverCreate(callback, acceptList) { function ObserverGetCallback(observer) { - return IS_SPEC_FUNCTION(observer) ? observer : observer.callback; + return IS_CALLABLE(observer) ? observer : observer.callback; } function ObserverGetAcceptTypes(observer) { - return IS_SPEC_FUNCTION(observer) ? defaultAcceptTypes : observer.accept; + return IS_CALLABLE(observer) ? defaultAcceptTypes : observer.accept; } @@ -238,8 +238,8 @@ function ObjectInfoGetNotifier(objectInfo) { function ChangeObserversIsOptimized(changeObservers) { - return IS_SPEC_FUNCTION(changeObservers) || - IS_SPEC_FUNCTION(changeObservers.callback); + return IS_CALLABLE(changeObservers) || + IS_CALLABLE(changeObservers.callback); } @@ -388,7 +388,7 @@ function ObjectObserve(object, callback, acceptList) { throw MakeTypeError(kObserveNonObject, "observe", "observe"); if (%IsJSGlobalProxy(object)) throw MakeTypeError(kObserveGlobalProxy, "observe"); - if (!IS_SPEC_FUNCTION(callback)) + if (!IS_CALLABLE(callback)) throw MakeTypeError(kObserveNonFunction, "observe"); if (ObjectIsFrozen(callback)) throw MakeTypeError(kObserveCallbackFrozen); @@ -411,7 +411,7 @@ function ObjectUnobserve(object, callback) { throw MakeTypeError(kObserveNonObject, "unobserve", "unobserve"); if (%IsJSGlobalProxy(object)) throw MakeTypeError(kObserveGlobalProxy, "unobserve"); - if (!IS_SPEC_FUNCTION(callback)) + if (!IS_CALLABLE(callback)) throw MakeTypeError(kObserveNonFunction, "unobserve"); var objectInfo = ObjectInfoGet(object); @@ -588,7 +588,7 @@ function ObjectNotifierPerformChange(changeType, changeFn) { throw MakeTypeError(kObserveNotifyNonNotifier); if (!IS_STRING(changeType)) throw MakeTypeError(kObservePerformNonString); - if (!IS_SPEC_FUNCTION(changeFn)) + if (!IS_CALLABLE(changeFn)) throw MakeTypeError(kObservePerformNonFunction); var performChangeFn = %GetObjectContextNotifierPerformChange(objectInfo); @@ -656,7 +656,7 @@ function CallbackDeliverPending(callback) { function ObjectDeliverChangeRecords(callback) { - if (!IS_SPEC_FUNCTION(callback)) + if (!IS_CALLABLE(callback)) throw MakeTypeError(kObserveNonFunction, "deliverChangeRecords"); while (CallbackDeliverPending(callback)) {} diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 0dafe03e7..889a76094 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -36,6 +36,7 @@ void Object::VerifyPointer(Object* p) { void Smi::SmiVerify() { CHECK(IsSmi()); + CHECK(!IsCallable()); } @@ -533,6 +534,7 @@ void JSFunction::JSFunctionVerify() { CHECK(next_function_link() == NULL || next_function_link()->IsUndefined() || next_function_link()->IsJSFunction()); + CHECK(map()->is_callable()); } @@ -811,6 +813,7 @@ void JSFunctionProxy::JSFunctionProxyVerify() { JSProxyVerify(); VerifyPointer(call_trap()); VerifyPointer(construct_trap()); + CHECK(map()->is_callable()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index fb5746196..794e017de 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -187,12 +187,18 @@ bool Object::IsUniqueName() const { } +bool Object::IsCallable() const { + return Object::IsHeapObject() && HeapObject::cast(this)->map()->is_callable(); +} + + bool Object::IsSpecObject() const { return Object::IsHeapObject() && HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE; } +// TODO(rossberg): Remove this and use the spec compliant IsCallable instead. bool Object::IsSpecFunction() const { if (!Object::IsHeapObject()) return false; InstanceType type = HeapObject::cast(this)->map()->instance_type(); @@ -4524,12 +4530,12 @@ bool Map::function_with_prototype() { void Map::set_is_hidden_prototype() { - set_bit_field(bit_field() | (1 << kIsHiddenPrototype)); + set_bit_field3(IsHiddenPrototype::update(bit_field3(), true)); } -bool Map::is_hidden_prototype() { - return ((1 << kIsHiddenPrototype) & bit_field()) != 0; +bool Map::is_hidden_prototype() const { + return IsHiddenPrototype::decode(bit_field3()); } @@ -4675,13 +4681,11 @@ bool Map::owns_descriptors() { } -void Map::set_has_instance_call_handler() { - set_bit_field3(HasInstanceCallHandler::update(bit_field3(), true)); -} +void Map::set_is_callable() { set_bit_field(bit_field() | (1 << kIsCallable)); } -bool Map::has_instance_call_handler() { - return HasInstanceCallHandler::decode(bit_field3()); +bool Map::is_callable() const { + return ((1 << kIsCallable) & bit_field()) != 0; } @@ -6293,7 +6297,7 @@ int JSFunction::NumberOfLiterals() { ACCESSORS(JSProxy, handler, Object, kHandlerOffset) ACCESSORS(JSProxy, hash, Object, kHashOffset) -ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset) +ACCESSORS(JSFunctionProxy, call_trap, JSReceiver, kCallTrapOffset) ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 73fa5b12e..6cab6fd3a 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -453,7 +453,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT if (has_named_interceptor()) os << " - named_interceptor\n"; if (has_indexed_interceptor()) os << " - indexed_interceptor\n"; if (is_undetectable()) os << " - undetectable\n"; - if (has_instance_call_handler()) os << " - instance_call_handler\n"; + if (is_callable()) os << " - callable\n"; if (is_access_check_needed()) os << " - access_check_needed\n"; if (!is_extensible()) os << " - non-extensible\n"; if (is_observed()) os << " - observed\n"; diff --git a/src/objects.cc b/src/objects.cc index 4214c8b78..c0539c493 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -176,14 +176,20 @@ bool Object::StrictEquals(Object* that) { } -bool Object::IsCallable() const { - const Object* fun = this; - while (fun->IsJSFunctionProxy()) { - fun = JSFunctionProxy::cast(fun)->call_trap(); +// static +Handle Object::TypeOf(Isolate* isolate, Handle object) { + if (object->IsNumber()) return isolate->factory()->number_string(); + if (object->IsUndefined() || object->IsUndetectableObject()) { + return isolate->factory()->undefined_string(); } - return fun->IsJSFunction() || - (fun->IsHeapObject() && - HeapObject::cast(fun)->map()->has_instance_call_handler()); + if (object->IsBoolean()) return isolate->factory()->boolean_string(); + if (object->IsSymbol()) return isolate->factory()->symbol_string(); +#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ + if (object->Is##Type()) return isolate->factory()->type##_string(); + SIMD128_TYPES(SIMD128_TYPE) +#undef SIMD128_TYPE + if (object->IsCallable()) return isolate->factory()->function_string(); + return isolate->factory()->object_string(); } @@ -9527,17 +9533,20 @@ int Map::Hash() { } -static bool CheckEquivalent(Map* first, Map* second) { +namespace { + +bool CheckEquivalent(Map* first, Map* second) { return first->GetConstructor() == second->GetConstructor() && first->prototype() == second->prototype() && first->instance_type() == second->instance_type() && first->bit_field() == second->bit_field() && first->is_extensible() == second->is_extensible() && first->is_strong() == second->is_strong() && - first->has_instance_call_handler() == - second->has_instance_call_handler(); + first->is_hidden_prototype() == second->is_hidden_prototype(); } +} // namespace + bool Map::EquivalentToForTransition(Map* other) { return CheckEquivalent(this, other); diff --git a/src/objects.h b/src/objects.h index 869253741..0c9a6d20f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1016,7 +1016,11 @@ class Object { STRUCT_LIST(DECLARE_STRUCT_PREDICATE) #undef DECLARE_STRUCT_PREDICATE + // ES6, section 7.2.3 IsCallable. + INLINE(bool IsCallable() const); + INLINE(bool IsSpecObject()) const; + // TODO(rossberg): IsSpecFunction should be removed in favor of IsCallable. INLINE(bool IsSpecFunction()) const; INLINE(bool IsTemplateInfo()) const; INLINE(bool IsNameDictionary() const); @@ -1025,7 +1029,6 @@ class Object { INLINE(bool IsUnseededNumberDictionary() const); INLINE(bool IsOrderedHashSet() const); INLINE(bool IsOrderedHashMap() const); - bool IsCallable() const; static bool IsPromise(Handle object); // Oddball testing. @@ -1107,6 +1110,9 @@ class Object { MUST_USE_RESULT static MaybeHandle GetMethod( Handle receiver, Handle name); + // ES6 section 12.5.6 The typeof Operator + static Handle TypeOf(Isolate* isolate, Handle object); + MUST_USE_RESULT static MaybeHandle GetProperty( LookupIterator* it, LanguageMode language_mode = SLOPPY); @@ -5233,7 +5239,7 @@ class Map: public HeapObject { STATIC_ASSERT(kDescriptorIndexBitCount + kDescriptorIndexBitCount == 20); class DictionaryMap : public BitField {}; class OwnsDescriptors : public BitField {}; - class HasInstanceCallHandler : public BitField {}; + class IsHiddenPrototype : public BitField {}; class Deprecated : public BitField {}; class IsUnstable : public BitField {}; class IsMigrationTarget : public BitField {}; @@ -5268,7 +5274,7 @@ class Map: public HeapObject { // Tells whether the instance with this map should be ignored by the // Object.getPrototypeOf() function and the __proto__ accessor. inline void set_is_hidden_prototype(); - inline bool is_hidden_prototype(); + inline bool is_hidden_prototype() const; // Records and queries whether the instance has a named interceptor. inline void set_has_named_interceptor(); @@ -5291,6 +5297,11 @@ class Map: public HeapObject { inline void set_is_observed(); inline bool is_observed(); + // Tells whether the instance has a [[Call]] internal field. + // This property is implemented according to ES6, section 7.2.3. + inline void set_is_callable(); + inline bool is_callable() const; + inline void set_is_strong(); inline bool is_strong(); inline void set_is_extensible(bool value); @@ -5466,8 +5477,6 @@ class Map: public HeapObject { inline bool owns_descriptors(); inline void set_owns_descriptors(bool owns_descriptors); - inline bool has_instance_call_handler(); - inline void set_has_instance_call_handler(); inline void mark_unstable(); inline bool is_stable(); inline void set_migration_target(bool value); @@ -5716,7 +5725,7 @@ class Map: public HeapObject { // Bit positions for bit field. static const int kHasNonInstancePrototype = 0; - static const int kIsHiddenPrototype = 1; + static const int kIsCallable = 1; static const int kHasNamedInterceptor = 2; static const int kHasIndexedInterceptor = 3; static const int kIsUndetectable = 4; @@ -9298,7 +9307,7 @@ class JSProxy: public JSReceiver { class JSFunctionProxy: public JSProxy { public: // [call_trap]: The call trap. - DECL_ACCESSORS(call_trap, Object) + DECL_ACCESSORS(call_trap, JSReceiver) // [construct_trap]: The construct trap. DECL_ACCESSORS(construct_trap, Object) diff --git a/src/promise.js b/src/promise.js index 08721956c..f119a0a94 100644 --- a/src/promise.js +++ b/src/promise.js @@ -30,7 +30,7 @@ var lastMicrotaskId = 0; var GlobalPromise = function Promise(resolver) { if (resolver === promiseRawSymbol) return; if (!%_IsConstructCall()) throw MakeTypeError(kNotAPromise, this); - if (!IS_SPEC_FUNCTION(resolver)) + if (!IS_CALLABLE(resolver)) throw MakeTypeError(kResolverNotAFunction, resolver); var promise = PromiseInit(this); try { @@ -85,7 +85,7 @@ function PromiseCoerce(constructor, x) { } catch(r) { return %_CallFunction(constructor, r, PromiseRejected); } - if (IS_SPEC_FUNCTION(then)) { + if (IS_CALLABLE(then)) { var deferred = %_CallFunction(constructor, PromiseDeferred); try { %_CallFunction(x, deferred.resolve, deferred.reject, then); @@ -259,10 +259,8 @@ function PromiseCatch(onReject) { // Multi-unwrapped chaining with thenable coercion. function PromiseThen(onResolve, onReject) { - onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve - : PromiseIdResolveHandler; - onReject = IS_SPEC_FUNCTION(onReject) ? onReject - : PromiseIdRejectHandler; + onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler; + onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; var that = this; var constructor = this.constructor; return %_CallFunction( diff --git a/src/proxy.js b/src/proxy.js index c8ad42ff8..fbca982d8 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -35,11 +35,11 @@ function ProxyCreate(handler, proto) { function ProxyCreateFunction(handler, callTrap, constructTrap) { if (!IS_SPEC_OBJECT(handler)) throw MakeTypeError(kProxyHandlerNonObject, "createFunction") - if (!IS_SPEC_FUNCTION(callTrap)) + if (!IS_CALLABLE(callTrap)) throw MakeTypeError(kProxyTrapFunctionExpected, "call") if (IS_UNDEFINED(constructTrap)) { constructTrap = DerivedConstructTrap(callTrap) - } else if (IS_SPEC_FUNCTION(constructTrap)) { + } else if (IS_CALLABLE(constructTrap)) { // Make sure the trap receives 'undefined' as this. var construct = constructTrap constructTrap = function() { diff --git a/src/runtime.js b/src/runtime.js index 8063a790e..880b7dea1 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -441,22 +441,12 @@ function IN(x) { function CALL_NON_FUNCTION() { var delegate = %GetFunctionDelegate(this); - if (!IS_FUNCTION(delegate)) { - var callsite = %RenderCallSite(); - if (callsite == "") callsite = typeof this; - throw %make_type_error(kCalledNonCallable, callsite); - } return %Apply(delegate, this, arguments, 0, %_ArgumentsLength()); } function CALL_NON_FUNCTION_AS_CONSTRUCTOR() { var delegate = %GetConstructorDelegate(this); - if (!IS_FUNCTION(delegate)) { - var callsite = %RenderCallSite(); - if (callsite == "") callsite = typeof this; - throw %make_type_error(kCalledNonCallable, callsite); - } return %Apply(delegate, this, arguments, 0, %_ArgumentsLength()); } @@ -484,7 +474,7 @@ function APPLY_PREPARE(args) { if (IS_ARRAY(args)) { length = args.length; if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength && - IS_SPEC_FUNCTION(this)) { + IS_CALLABLE(this)) { return length; } } @@ -496,8 +486,9 @@ function APPLY_PREPARE(args) { // multiplying with pointer size. if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow); - if (!IS_SPEC_FUNCTION(this)) { - throw %make_type_error(kApplyNonFunction, %to_string_fun(this), typeof this); + if (!IS_CALLABLE(this)) { + throw %make_type_error(kApplyNonFunction, %to_string_fun(this), + typeof this); } // Make sure the arguments list has the right type. @@ -519,12 +510,12 @@ function REFLECT_APPLY_PREPARE(args) { if (IS_ARRAY(args)) { length = args.length; if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength && - IS_SPEC_FUNCTION(this)) { + IS_CALLABLE(this)) { return length; } } - if (!IS_SPEC_FUNCTION(this)) { + if (!IS_CALLABLE(this)) { throw %make_type_error(kCalledNonCallable, %to_string_fun(this)); } @@ -548,8 +539,8 @@ function REFLECT_APPLY_PREPARE(args) { function REFLECT_CONSTRUCT_PREPARE( args, newTarget) { var length; - var ctorOk = IS_SPEC_FUNCTION(this) && %IsConstructor(this); - var newTargetOk = IS_SPEC_FUNCTION(newTarget) && %IsConstructor(newTarget); + var ctorOk = IS_CALLABLE(this) && %IsConstructor(this); + var newTargetOk = IS_CALLABLE(newTarget) && %IsConstructor(newTarget); // First check whether length is a positive Smi and args is an // array. This is the fast case. If this fails, we do the slow case @@ -563,7 +554,7 @@ function REFLECT_CONSTRUCT_PREPARE( } if (!ctorOk) { - if (!IS_SPEC_FUNCTION(this)) { + if (!IS_CALLABLE(this)) { throw %make_type_error(kCalledNonCallable, %to_string_fun(this)); } else { throw %make_type_error(kNotConstructor, %to_string_fun(this)); @@ -571,7 +562,7 @@ function REFLECT_CONSTRUCT_PREPARE( } if (!newTargetOk) { - if (!IS_SPEC_FUNCTION(newTarget)) { + if (!IS_CALLABLE(newTarget)) { throw %make_type_error(kCalledNonCallable, %to_string_fun(newTarget)); } else { throw %make_type_error(kNotConstructor, %to_string_fun(newTarget)); @@ -751,14 +742,14 @@ function IsConcatSpreadable(O) { // ECMA-262, section 8.6.2.6, page 28. function DefaultNumber(x) { var valueOf = x.valueOf; - if (IS_SPEC_FUNCTION(valueOf)) { + if (IS_CALLABLE(valueOf)) { var v = %_CallFunction(x, valueOf); if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber); if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber); if (IsPrimitive(v)) return v; } var toString = x.toString; - if (IS_SPEC_FUNCTION(toString)) { + if (IS_CALLABLE(toString)) { var s = %_CallFunction(x, toString); if (IsPrimitive(s)) return s; } @@ -770,13 +761,13 @@ function DefaultString(x) { if (!IS_SYMBOL_WRAPPER(x)) { if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString); var toString = x.toString; - if (IS_SPEC_FUNCTION(toString)) { + if (IS_CALLABLE(toString)) { var s = %_CallFunction(x, toString); if (IsPrimitive(s)) return s; } var valueOf = x.valueOf; - if (IS_SPEC_FUNCTION(valueOf)) { + if (IS_CALLABLE(valueOf)) { var v = %_CallFunction(x, valueOf); if (IsPrimitive(v)) return v; } diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index d1c8568e5..a66fe393b 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -80,7 +80,7 @@ RUNTIME_FUNCTION(Runtime_ToMethod) { CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); Handle clone = JSFunction::CloneClosure(fun); - Handle home_object_symbol(isolate->heap()->home_object_symbol()); + Handle home_object_symbol(isolate->factory()->home_object_symbol()); JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol, home_object, DONT_ENUM).Assert(); return *clone; @@ -105,7 +105,7 @@ static MaybeHandle DefineClass(Isolate* isolate, Handle name, } else { if (super_class->IsNull()) { prototype_parent = isolate->factory()->null_value(); - } else if (super_class->IsSpecFunction()) { + } else if (super_class->IsJSFunction()) { // TODO(bmeurer): IsConstructor. if (Handle::cast(super_class)->shared()->is_generator()) { THROW_NEW_ERROR( isolate, @@ -126,7 +126,6 @@ static MaybeHandle DefineClass(Isolate* isolate, Handle name, } constructor_parent = super_class; } else { - // TODO(arv): Should be IsConstructor. THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kExtendsValueNotFunction, super_class), diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc index d92d13ec1..a00ca4b73 100644 --- a/src/runtime/runtime-function.cc +++ b/src/runtime/runtime-function.cc @@ -22,10 +22,10 @@ RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) { CONVERT_ARG_CHECKED(JSReceiver, callable, 0); if (!callable->IsJSFunction()) { HandleScope scope(isolate); - Handle delegate; + Handle delegate; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, delegate, Execution::TryGetFunctionDelegate( - isolate, Handle(callable))); + isolate, delegate, + Execution::GetFunctionDelegate(isolate, Handle(callable))); callable = JSFunction::cast(*delegate); } JSFunction* function = JSFunction::cast(callable); @@ -515,7 +515,7 @@ RUNTIME_FUNCTION(Runtime_NewObjectFromBound) { if (!bound_function->IsJSFunction()) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, bound_function, - Execution::TryGetConstructorDelegate(isolate, bound_function)); + Execution::GetConstructorDelegate(isolate, bound_function)); } DCHECK(bound_function->IsJSFunction()); @@ -602,7 +602,10 @@ RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) { DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); RUNTIME_ASSERT(!object->IsJSFunction()); - return *Execution::GetFunctionDelegate(isolate, object); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, Execution::GetFunctionDelegate(isolate, object)); + return *result; } @@ -611,7 +614,10 @@ RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) { DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); RUNTIME_ASSERT(!object->IsJSFunction()); - return *Execution::GetConstructorDelegate(isolate, object); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, Execution::GetConstructorDelegate(isolate, object)); + return *result; } diff --git a/src/runtime/runtime-internal.cc b/src/runtime/runtime-internal.cc index b578c257f..0127f2381 100644 --- a/src/runtime/runtime-internal.cc +++ b/src/runtime/runtime-internal.cc @@ -11,8 +11,6 @@ #include "src/frames-inl.h" #include "src/isolate-inl.h" #include "src/messages.h" -#include "src/parser.h" -#include "src/prettyprinter.h" namespace v8 { namespace internal { @@ -261,30 +259,6 @@ RUNTIME_FUNCTION(Runtime_CollectStackTrace) { } -RUNTIME_FUNCTION(Runtime_RenderCallSite) { - HandleScope scope(isolate); - DCHECK(args.length() == 0); - MessageLocation location; - if (!isolate->ComputeLocation(&location)) { - return isolate->heap()->empty_string(); - } - - Zone zone; - base::SmartPointer info( - location.function()->shared()->is_function() - ? new ParseInfo(&zone, location.function()) - : new ParseInfo(&zone, location.script())); - - if (!Parser::ParseStatic(info.get())) { - isolate->clear_pending_exception(); - return isolate->heap()->empty_string(); - } - CallPrinter printer(isolate, &zone); - const char* string = printer.Print(info->literal(), location.start_pos()); - return *isolate->factory()->NewStringFromAsciiChecked(string); -} - - RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); diff --git a/src/runtime/runtime-proxy.cc b/src/runtime/runtime-proxy.cc index 03af691cf..4699647b8 100644 --- a/src/runtime/runtime-proxy.cc +++ b/src/runtime/runtime-proxy.cc @@ -25,7 +25,7 @@ RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) { HandleScope scope(isolate); DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, call_trap, 1); RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2); CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index e802da28f..d0738a006 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -321,7 +321,6 @@ namespace internal { F(AllocateInNewSpace, 1, 1) \ F(AllocateInTargetSpace, 2, 1) \ F(CollectStackTrace, 2, 1) \ - F(RenderCallSite, 0, 1) \ F(MessageGetStartPosition, 1, 1) \ F(MessageGetScript, 1, 1) \ F(ErrorToStringRT, 1, 1) \ diff --git a/src/string.js b/src/string.js index 08129584c..1bbc8a69c 100644 --- a/src/string.js +++ b/src/string.js @@ -250,7 +250,7 @@ function StringReplace(search, replace) { var lastIndex = search.lastIndex; TO_INTEGER_FOR_SIDE_EFFECT(lastIndex); - if (!IS_SPEC_FUNCTION(replace)) { + if (!IS_CALLABLE(replace)) { replace = TO_STRING_INLINE(replace); if (!search.global) { @@ -317,7 +317,7 @@ function StringReplace(search, replace) { var result = %_SubString(subject, 0, start); // Compute the string to replace with. - if (IS_SPEC_FUNCTION(replace)) { + if (IS_CALLABLE(replace)) { var receiver = UNDEFINED; result += %_CallFunction(receiver, search, start, subject, replace); } else { diff --git a/src/v8natives.js b/src/v8natives.js index fbe69578b..a9306003b 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -217,7 +217,7 @@ function ObjectDefineGetter(name, fun) { if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { receiver = %GlobalProxy(ObjectDefineGetter); } - if (!IS_SPEC_FUNCTION(fun)) { + if (!IS_CALLABLE(fun)) { throw MakeTypeError(kObjectGetterExpectingFunction); } var desc = new PropertyDescriptor(); @@ -242,7 +242,7 @@ function ObjectDefineSetter(name, fun) { if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { receiver = %GlobalProxy(ObjectDefineSetter); } - if (!IS_SPEC_FUNCTION(fun)) { + if (!IS_CALLABLE(fun)) { throw MakeTypeError(kObjectSetterExpectingFunction); } var desc = new PropertyDescriptor(); @@ -368,7 +368,7 @@ function ToPropertyDescriptor(obj) { if ("get" in obj) { var get = obj.get; - if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) { + if (!IS_UNDEFINED(get) && !IS_CALLABLE(get)) { throw MakeTypeError(kObjectGetterCallable, get); } desc.setGet(get); @@ -376,7 +376,7 @@ function ToPropertyDescriptor(obj) { if ("set" in obj) { var set = obj.set; - if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) { + if (!IS_UNDEFINED(set) && !IS_CALLABLE(set)) { throw MakeTypeError(kObjectSetterCallable, set); } desc.setSet(set); @@ -536,7 +536,7 @@ function GetTrap(handler, name, defaultTrap) { throw MakeTypeError(kProxyHandlerTrapMissing, handler, name); } trap = defaultTrap; - } else if (!IS_SPEC_FUNCTION(trap)) { + } else if (!IS_CALLABLE(trap)) { throw MakeTypeError(kProxyHandlerTrapMustBeCallable, handler, name); } return trap; @@ -605,7 +605,7 @@ function Delete(obj, p, should_throw) { function GetMethod(obj, p) { var func = obj[p]; if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED; - if (IS_SPEC_FUNCTION(func)) return func; + if (IS_CALLABLE(func)) return func; throw MakeTypeError(kCalledNonCallable, typeof func); } @@ -1658,7 +1658,7 @@ function FunctionToString() { // ES5 15.3.4.5 function FunctionBind(this_arg) { // Length is 1. - if (!IS_SPEC_FUNCTION(this)) throw MakeTypeError(kFunctionBind); + if (!IS_CALLABLE(this)) throw MakeTypeError(kFunctionBind); var boundFunction = function () { // Poison .arguments and .caller, but is otherwise not detectable. @@ -1774,7 +1774,7 @@ function GetIterator(obj, method) { if (IS_UNDEFINED(method)) { method = obj[iteratorSymbol]; } - if (!IS_SPEC_FUNCTION(method)) { + if (!IS_CALLABLE(method)) { throw MakeTypeError(kNotIterable, obj); } var iterator = %_CallFunction(obj, method); diff --git a/src/weak-collection.js b/src/weak-collection.js index 933d753f3..67deddb95 100644 --- a/src/weak-collection.js +++ b/src/weak-collection.js @@ -25,7 +25,7 @@ function WeakMapConstructor(iterable) { if (!IS_NULL_OR_UNDEFINED(iterable)) { var adder = this.set; - if (!IS_SPEC_FUNCTION(adder)) { + if (!IS_CALLABLE(adder)) { throw MakeTypeError(kPropertyNotFunction, 'set', this); } for (var nextItem of iterable) { @@ -114,7 +114,7 @@ function WeakSetConstructor(iterable) { if (!IS_NULL_OR_UNDEFINED(iterable)) { var adder = this.add; - if (!IS_SPEC_FUNCTION(adder)) { + if (!IS_CALLABLE(adder)) { throw MakeTypeError(kPropertyNotFunction, 'add', this); } for (var value of iterable) { diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 4e1ac86ae..250589097 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5617,32 +5617,33 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { final_branch_condition = not_zero; } else if (String::Equals(type_name, factory->function_string())) { - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label, false_distance); - __ CmpObjectType(input, JS_FUNCTION_TYPE, input); - __ j(equal, true_label, true_distance); - __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); + // Check for callable and not undetectable objects => true. + __ movp(input, FieldOperand(input, HeapObject::kMapOffset)); + __ movzxbl(input, FieldOperand(input, Map::kBitFieldOffset)); + __ andb(input, + Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); + __ cmpb(input, Immediate(1 << Map::kIsCallable)); final_branch_condition = equal; } else if (String::Equals(type_name, factory->object_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CompareRoot(input, Heap::kNullValueRootIndex); __ j(equal, true_label, true_distance); - __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); + STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, input); __ j(below, false_label, false_distance); - __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); - __ j(above, false_label, false_distance); - // Check for undetectable objects => false. + // Check for callable or undetectable objects => false. __ testb(FieldOperand(input, Map::kBitFieldOffset), - Immediate(1 << Map::kIsUndetectable)); + Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); final_branch_condition = zero; // clang-format off #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ } else if (String::Equals(type_name, factory->type##_string())) { \ __ JumpIfSmi(input, false_label, false_distance); \ - __ movp(input, FieldOperand(input, HeapObject::kMapOffset)); \ - __ CompareRoot(input, Heap::k##Type##MapRootIndex); \ + __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), \ + Heap::k##Type##MapRootIndex); \ final_branch_condition = equal; SIMD128_TYPES(SIMD128_TYPE) #undef SIMD128_TYPE diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 9b1228295..3a80397e7 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -9795,8 +9795,8 @@ THREADED_TEST(ConstructorForObject) { value = instance->CallAsConstructor(1, args); CHECK(try_catch.HasCaught()); String::Utf8Value exception_value2(try_catch.Exception()); - CHECK_EQ( - 0, strcmp("TypeError: # is not a function", *exception_value2)); + CHECK_EQ(0, + strcmp("TypeError: object is not a function", *exception_value2)); try_catch.Reset(); } @@ -10165,8 +10165,8 @@ THREADED_TEST(CallAsFunction) { CHECK(value.IsEmpty()); CHECK(try_catch.HasCaught()); String::Utf8Value exception_value2(try_catch.Exception()); - CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function", - *exception_value2)); + CHECK_EQ(0, + strcmp("TypeError: object is not a function", *exception_value2)); try_catch.Reset(); } -- 2.34.1