v8/src/contexts-inl.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

229 lines
7.4 KiB
C
Raw Normal View History

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CONTEXTS_INL_H_
#define V8_CONTEXTS_INL_H_
#include "src/contexts.h"
#include "src/heap/heap.h"
#include "src/objects-inl.h"
#include "src/objects/dictionary.h"
#include "src/objects/map-inl.h"
#include "src/objects/regexp-match-info.h"
#include "src/objects/shared-function-info-inl.h"
[es2015] Introduce dedicated GetTemplateObject bytecode. Tagged templates were previously desugared during parsing using some combination of runtime support written in JavaScript and C++, which prevented some optimizations from happening, namely the constant folding of the template object in TurboFan optimized code. This CL adds a new bytecode GetTemplateObject (with a corresponding GetTemplateObject AST node), which represents the abstract operation in the ES6 specification and allows TurboFan to simply constant-fold template objects at compile time (which is explicitly supported by the specification). This also pays down some technical debt by removing the template.js runtime support and therefore should reduce the size of the native context (snapshot) a bit. With this change in-place the ES6 version microbenchmark in the referenced tracking bug is now faster than the transpiled Babel code, it goes from templateStringTagES5: 4552 ms. templateStringTagES6: 14185 ms. templateStringTagBabel: 7626 ms. to templateStringTagES5: 4515 ms. templateStringTagES6: 7491 ms. templateStringTagBabel: 7639 ms. which corresponds to a solid 45% reduction in execution time. With some further optimizations the ES6 version should be able to outperform the ES5 version. This micro-benchmark should be fairly representative of the six-speed-templatestringtag-es6 benchmark, and as such that benchmark should also improve by around 50%. Bug: v8:6819,v8:6820 Tbr: mlippautz@chromium.org Change-Id: I821085e3794717fc7f52b5c306fcb93ba03345dc Reviewed-on: https://chromium-review.googlesource.com/677462 Reviewed-by: Mythri Alle <mythria@chromium.org> Reviewed-by: Caitlin Potter <caitp@igalia.com> Reviewed-by: Adam Klein <adamk@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#48126}
2017-09-22 09:57:29 +00:00
#include "src/objects/template-objects.h"
namespace v8 {
namespace internal {
// static
ScriptContextTable* ScriptContextTable::cast(Object* context) {
DCHECK(context->IsScriptContextTable());
return reinterpret_cast<ScriptContextTable*>(context);
}
int ScriptContextTable::used() const { return Smi::ToInt(get(kUsedSlot)); }
void ScriptContextTable::set_used(int used) {
set(kUsedSlot, Smi::FromInt(used));
}
// static
Handle<Context> ScriptContextTable::GetContext(Handle<ScriptContextTable> table,
int i) {
DCHECK(i < table->used());
return Handle<Context>::cast(
FixedArray::get(*table, i + kFirstContextSlot, table->GetIsolate()));
}
// static
Context* Context::cast(Object* context) {
DCHECK(context->IsContext());
return reinterpret_cast<Context*>(context);
}
JSFunction* Context::closure() { return JSFunction::cast(get(CLOSURE_INDEX)); }
void Context::set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); }
Context* Context::previous() {
Object* result = get(PREVIOUS_INDEX);
DCHECK(IsBootstrappingOrValidParentContext(result, this));
return reinterpret_cast<Context*>(result);
}
void Context::set_previous(Context* context) { set(PREVIOUS_INDEX, context); }
Object* Context::next_context_link() { return get(Context::NEXT_CONTEXT_LINK); }
bool Context::has_extension() { return !extension()->IsTheHole(GetIsolate()); }
HeapObject* Context::extension() {
return HeapObject::cast(get(EXTENSION_INDEX));
}
void Context::set_extension(HeapObject* object) {
set(EXTENSION_INDEX, object);
}
Context* Context::native_context() const {
Object* result = get(NATIVE_CONTEXT_INDEX);
DCHECK(IsBootstrappingOrNativeContext(this->GetIsolate(), result));
return reinterpret_cast<Context*>(result);
}
void Context::set_native_context(Context* context) {
set(NATIVE_CONTEXT_INDEX, context);
}
bool Context::IsNativeContext() const {
Map* map = this->map();
return map == map->GetHeap()->native_context_map();
}
bool Context::IsFunctionContext() const {
Map* map = this->map();
return map == map->GetHeap()->function_context_map();
}
bool Context::IsCatchContext() const {
Map* map = this->map();
return map == map->GetHeap()->catch_context_map();
}
bool Context::IsWithContext() const {
Map* map = this->map();
return map == map->GetHeap()->with_context_map();
}
bool Context::IsDebugEvaluateContext() const {
Map* map = this->map();
return map == map->GetHeap()->debug_evaluate_context_map();
}
bool Context::IsBlockContext() const {
Map* map = this->map();
return map == map->GetHeap()->block_context_map();
}
bool Context::IsModuleContext() const {
Map* map = this->map();
return map == map->GetHeap()->module_context_map();
}
bool Context::IsEvalContext() const {
Map* map = this->map();
return map == map->GetHeap()->eval_context_map();
}
bool Context::IsScriptContext() const {
Map* map = this->map();
return map == map->GetHeap()->script_context_map();
}
bool Context::HasSameSecurityTokenAs(Context* that) const {
return this->native_context()->security_token() ==
that->native_context()->security_token();
}
#define NATIVE_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void Context::set_##name(type* value) { \
DCHECK(IsNativeContext()); \
set(index, value); \
} \
bool Context::is_##name(type* value) const { \
DCHECK(IsNativeContext()); \
return type::cast(get(index)) == value; \
} \
type* Context::name() const { \
DCHECK(IsNativeContext()); \
return type::cast(get(index)); \
}
NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELD_ACCESSORS)
#undef NATIVE_CONTEXT_FIELD_ACCESSORS
#define CHECK_FOLLOWS2(v1, v2) STATIC_ASSERT((v1 + 1) == (v2))
#define CHECK_FOLLOWS4(v1, v2, v3, v4) \
CHECK_FOLLOWS2(v1, v2); \
CHECK_FOLLOWS2(v2, v3); \
CHECK_FOLLOWS2(v3, v4)
int Context::FunctionMapIndex(LanguageMode language_mode, FunctionKind kind,
bool has_prototype_slot, bool has_shared_name,
bool needs_home_object) {
if (IsClassConstructor(kind)) {
// Like the strict function map, but with no 'name' accessor. 'name'
// needs to be the last property and it is added during instantiation,
// in case a static property with the same name exists"
return CLASS_FUNCTION_MAP_INDEX;
}
int base = 0;
if (IsGeneratorFunction(kind)) {
CHECK_FOLLOWS4(GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_FUNCTION_WITH_NAME_MAP_INDEX,
GENERATOR_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
GENERATOR_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
CHECK_FOLLOWS4(
ASYNC_GENERATOR_FUNCTION_MAP_INDEX,
ASYNC_GENERATOR_FUNCTION_WITH_NAME_MAP_INDEX,
ASYNC_GENERATOR_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
ASYNC_GENERATOR_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
base = IsAsyncFunction(kind) ? ASYNC_GENERATOR_FUNCTION_MAP_INDEX
: GENERATOR_FUNCTION_MAP_INDEX;
} else if (IsAsyncFunction(kind)) {
CHECK_FOLLOWS4(ASYNC_FUNCTION_MAP_INDEX, ASYNC_FUNCTION_WITH_NAME_MAP_INDEX,
ASYNC_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
ASYNC_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
base = ASYNC_FUNCTION_MAP_INDEX;
} else if (IsArrowFunction(kind) || IsConciseMethod(kind) ||
IsAccessorFunction(kind)) {
DCHECK_IMPLIES(IsArrowFunction(kind), !needs_home_object);
CHECK_FOLLOWS4(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
METHOD_WITH_NAME_MAP_INDEX,
METHOD_WITH_HOME_OBJECT_MAP_INDEX,
METHOD_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
base = STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
} else {
DCHECK(!needs_home_object);
CHECK_FOLLOWS2(SLOPPY_FUNCTION_MAP_INDEX,
SLOPPY_FUNCTION_WITH_NAME_MAP_INDEX);
CHECK_FOLLOWS2(STRICT_FUNCTION_MAP_INDEX,
STRICT_FUNCTION_WITH_NAME_MAP_INDEX);
base = is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
: SLOPPY_FUNCTION_MAP_INDEX;
}
int offset = static_cast<int>(!has_shared_name) |
(static_cast<int>(needs_home_object) << 1);
DCHECK_EQ(0, offset & ~3);
return base + offset;
}
#undef CHECK_FOLLOWS2
#undef CHECK_FOLLOWS4
Map* Context::GetInitialJSArrayMap(ElementsKind kind) const {
DCHECK(IsNativeContext());
if (!IsFastElementsKind(kind)) return nullptr;
DisallowHeapAllocation no_gc;
Object* const initial_js_array_map = get(Context::ArrayMapIndex(kind));
DCHECK(!initial_js_array_map->IsUndefined(GetIsolate()));
return Map::cast(initial_js_array_map);
}
} // namespace internal
} // namespace v8
#endif // V8_CONTEXTS_INL_H_