Split more runtime functions into seperate files.

R=bmeurer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/598913004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24274 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-09-29 09:32:38 +00:00
parent 6312804eb3
commit b0fdeb1b2a
10 changed files with 2703 additions and 2594 deletions

View File

@ -824,10 +824,16 @@ source_set("v8_base") {
"src/rewriter.h",
"src/runtime-profiler.cc",
"src/runtime-profiler.h",
"src/runtime/runtime-collections.cc",
"src/runtime/runtime-compiler.cc",
"src/runtime/runtime-i18n.cc",
"src/runtime/runtime-json.cc",
"src/runtime/runtime-maths.cc",
"src/runtime/runtime-numbers.cc",
"src/runtime/runtime-regexp.cc",
"src/runtime/runtime-strings.cc",
"src/runtime/runtime-test.cc",
"src/runtime/runtime-typedarray.cc",
"src/runtime/runtime-uri.cc",
"src/runtime/runtime-utils.h",
"src/runtime/runtime.cc",

View File

@ -0,0 +1,347 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_SetInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
holder->set_table(*table);
return *holder;
}
RUNTIME_FUNCTION(Runtime_SetAdd) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
table = OrderedHashSet::Add(table, key);
holder->set_table(*table);
return *holder;
}
RUNTIME_FUNCTION(Runtime_SetHas) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
return isolate->heap()->ToBoolean(table->Contains(key));
}
RUNTIME_FUNCTION(Runtime_SetDelete) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
bool was_present = false;
table = OrderedHashSet::Remove(table, key, &was_present);
holder->set_table(*table);
return isolate->heap()->ToBoolean(was_present);
}
RUNTIME_FUNCTION(Runtime_SetClear) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
table = OrderedHashSet::Clear(table);
holder->set_table(*table);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetGetSize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
return Smi::FromInt(table->NumberOfElements());
}
RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
CONVERT_SMI_ARG_CHECKED(kind, 2)
RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
kind == JSSetIterator::kKindEntries);
Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
holder->set_table(*table);
holder->set_index(Smi::FromInt(0));
holder->set_kind(Smi::FromInt(kind));
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
CONVERT_ARG_CHECKED(JSArray, value_array, 1);
return holder->Next(value_array);
}
RUNTIME_FUNCTION(Runtime_MapInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
holder->set_table(*table);
return *holder;
}
RUNTIME_FUNCTION(Runtime_MapGet) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
Handle<Object> lookup(table->Lookup(key), isolate);
return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
}
RUNTIME_FUNCTION(Runtime_MapHas) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
Handle<Object> lookup(table->Lookup(key), isolate);
return isolate->heap()->ToBoolean(!lookup->IsTheHole());
}
RUNTIME_FUNCTION(Runtime_MapDelete) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
bool was_present = false;
Handle<OrderedHashMap> new_table =
OrderedHashMap::Remove(table, key, &was_present);
holder->set_table(*new_table);
return isolate->heap()->ToBoolean(was_present);
}
RUNTIME_FUNCTION(Runtime_MapClear) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
table = OrderedHashMap::Clear(table);
holder->set_table(*table);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_MapSet) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value);
holder->set_table(*new_table);
return *holder;
}
RUNTIME_FUNCTION(Runtime_MapGetSize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
return Smi::FromInt(table->NumberOfElements());
}
RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
CONVERT_SMI_ARG_CHECKED(kind, 2)
RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys ||
kind == JSMapIterator::kKindValues ||
kind == JSMapIterator::kKindEntries);
Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
holder->set_table(*table);
holder->set_index(Smi::FromInt(0));
holder->set_kind(Smi::FromInt(kind));
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
Handle<FixedArray> entries =
isolate->factory()->NewFixedArray(table->NumberOfElements() * 2);
{
DisallowHeapAllocation no_gc;
int number_of_non_hole_elements = 0;
for (int i = 0; i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(*key)) {
entries->set(number_of_non_hole_elements++, *key);
Object* value = table->Lookup(key);
entries->set(number_of_non_hole_elements++, value);
}
}
DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements);
}
return *isolate->factory()->NewJSArrayWithElements(entries);
}
RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
CONVERT_ARG_CHECKED(JSArray, value_array, 1);
return holder->Next(value_array);
}
static Handle<JSWeakCollection> WeakCollectionInitialize(
Isolate* isolate, Handle<JSWeakCollection> weak_collection) {
DCHECK(weak_collection->map()->inobject_properties() == 0);
Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
weak_collection->set_table(*table);
return weak_collection;
}
RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
return *WeakCollectionInitialize(isolate, weak_collection);
}
RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
RUNTIME_ASSERT(table->IsKey(*key));
Handle<Object> lookup(table->Lookup(key), isolate);
return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
}
RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
RUNTIME_ASSERT(table->IsKey(*key));
Handle<Object> lookup(table->Lookup(key), isolate);
return isolate->heap()->ToBoolean(!lookup->IsTheHole());
}
RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
RUNTIME_ASSERT(table->IsKey(*key));
bool was_present = false;
Handle<ObjectHashTable> new_table =
ObjectHashTable::Remove(table, key, &was_present);
weak_collection->set_table(*new_table);
return isolate->heap()->ToBoolean(was_present);
}
RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
RUNTIME_ASSERT(table->IsKey(*key));
Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
weak_collection->set_table(*new_table);
return *weak_collection;
}
RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
Handle<FixedArray> values =
isolate->factory()->NewFixedArray(table->NumberOfElements());
{
DisallowHeapAllocation no_gc;
int number_of_non_hole_elements = 0;
for (int i = 0; i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(*key)) {
values->set(number_of_non_hole_elements++, *key);
}
}
DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements);
}
return *isolate->factory()->NewJSArrayWithElements(values);
}
RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
// TODO(adamk): Currently this runtime function is only called three times per
// isolate. If it's called more often, the map should be moved into the
// strong root list.
Handle<Map> map =
isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
Handle<JSWeakMap> weakmap =
Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
return *WeakCollectionInitialize(isolate, weakmap);
}
}
} // namespace v8::internal

View File

@ -0,0 +1,441 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/compiler.h"
#include "src/deoptimizer.h"
#include "src/frames.h"
#include "src/full-codegen.h"
#include "src/isolate.h"
#include "src/isolate-inl.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
#include "src/v8threads.h"
#include "src/vm-state.h"
#include "src/vm-state-inl.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_CompileLazy) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
#ifdef DEBUG
if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
PrintF("[unoptimized: ");
function->PrintName();
PrintF("]\n");
}
#endif
// Compile the target function.
DCHECK(function->shared()->allows_lazy_compilation());
Handle<Code> code;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
Compiler::GetLazyCode(function));
DCHECK(code->kind() == Code::FUNCTION ||
code->kind() == Code::OPTIMIZED_FUNCTION);
function->ReplaceCode(*code);
return *code;
}
RUNTIME_FUNCTION(Runtime_CompileOptimized) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
Handle<Code> unoptimized(function->shared()->code());
if (!isolate->use_crankshaft() ||
function->shared()->optimization_disabled() ||
isolate->DebuggerHasBreakPoints()) {
// If the function is not optimizable or debugger is active continue
// using the code from the full compiler.
if (FLAG_trace_opt) {
PrintF("[failed to optimize ");
function->PrintName();
PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
function->shared()->optimization_disabled() ? "F" : "T",
isolate->DebuggerHasBreakPoints() ? "T" : "F");
}
function->ReplaceCode(*unoptimized);
return function->code();
}
Compiler::ConcurrencyMode mode =
concurrent ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
Handle<Code> code;
if (Compiler::GetOptimizedCode(function, unoptimized, mode).ToHandle(&code)) {
function->ReplaceCode(*code);
} else {
function->ReplaceCode(function->shared()->code());
}
DCHECK(function->code()->kind() == Code::FUNCTION ||
function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
function->IsInOptimizationQueue());
return function->code();
}
RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
DCHECK(AllowHeapAllocation::IsAllowed());
delete deoptimizer;
return isolate->heap()->undefined_value();
}
class ActivationsFinder : public ThreadVisitor {
public:
Code* code_;
bool has_code_activations_;
explicit ActivationsFinder(Code* code)
: code_(code), has_code_activations_(false) {}
void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
JavaScriptFrameIterator it(isolate, top);
VisitFrames(&it);
}
void VisitFrames(JavaScriptFrameIterator* it) {
for (; !it->done(); it->Advance()) {
JavaScriptFrame* frame = it->frame();
if (code_->contains(frame->pc())) has_code_activations_ = true;
}
}
};
RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_SMI_ARG_CHECKED(type_arg, 0);
Deoptimizer::BailoutType type =
static_cast<Deoptimizer::BailoutType>(type_arg);
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
DCHECK(AllowHeapAllocation::IsAllowed());
Handle<JSFunction> function = deoptimizer->function();
Handle<Code> optimized_code = deoptimizer->compiled_code();
DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
DCHECK(type == deoptimizer->bailout_type());
// Make sure to materialize objects before causing any allocation.
JavaScriptFrameIterator it(isolate);
deoptimizer->MaterializeHeapObjects(&it);
delete deoptimizer;
JavaScriptFrame* frame = it.frame();
RUNTIME_ASSERT(frame->function()->IsJSFunction());
DCHECK(frame->function() == *function);
// Avoid doing too much work when running with --always-opt and keep
// the optimized code around.
if (FLAG_always_opt || type == Deoptimizer::LAZY) {
return isolate->heap()->undefined_value();
}
// Search for other activations of the same function and code.
ActivationsFinder activations_finder(*optimized_code);
activations_finder.VisitFrames(&it);
isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
if (!activations_finder.has_code_activations_) {
if (function->code() == *optimized_code) {
if (FLAG_trace_deopt) {
PrintF("[removing optimized code for: ");
function->PrintName();
PrintF("]\n");
}
function->ReplaceCode(function->shared()->code());
// Evict optimized code for this function from the cache so that it
// doesn't get used for new closures.
function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
"notify deoptimized");
}
} else {
// TODO(titzer): we should probably do DeoptimizeCodeList(code)
// unconditionally if the code is not already marked for deoptimization.
// If there is an index by shared function info, all the better.
Deoptimizer::DeoptimizeFunction(*function);
}
return isolate->heap()->undefined_value();
}
static bool IsSuitableForOnStackReplacement(Isolate* isolate,
Handle<JSFunction> function,
Handle<Code> current_code) {
// Keep track of whether we've succeeded in optimizing.
if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
// If we are trying to do OSR when there are already optimized
// activations of the function, it means (a) the function is directly or
// indirectly recursive and (b) an optimized invocation has been
// deoptimized so that we are currently in an unoptimized activation.
// Check for optimized activations of this function.
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
if (frame->is_optimized() && frame->function() == *function) return false;
}
return true;
}
RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Handle<Code> caller_code(function->shared()->code());
// We're not prepared to handle a function with arguments object.
DCHECK(!function->shared()->uses_arguments());
RUNTIME_ASSERT(FLAG_use_osr);
// Passing the PC in the javascript frame from the caller directly is
// not GC safe, so we walk the stack to get it.
JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame();
if (!caller_code->contains(frame->pc())) {
// Code on the stack may not be the code object referenced by the shared
// function info. It may have been replaced to include deoptimization data.
caller_code = Handle<Code>(frame->LookupCode());
}
uint32_t pc_offset =
static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
#ifdef DEBUG
DCHECK_EQ(frame->function(), *function);
DCHECK_EQ(frame->LookupCode(), *caller_code);
DCHECK(caller_code->contains(frame->pc()));
#endif // DEBUG
BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
DCHECK(!ast_id.IsNone());
Compiler::ConcurrencyMode mode =
isolate->concurrent_osr_enabled() &&
(function->shared()->ast_node_count() > 512)
? Compiler::CONCURRENT
: Compiler::NOT_CONCURRENT;
Handle<Code> result = Handle<Code>::null();
OptimizedCompileJob* job = NULL;
if (mode == Compiler::CONCURRENT) {
// Gate the OSR entry with a stack check.
BackEdgeTable::AddStackCheck(caller_code, pc_offset);
// Poll already queued compilation jobs.
OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
if (thread->IsQueuedForOSR(function, ast_id)) {
if (FLAG_trace_osr) {
PrintF("[OSR - Still waiting for queued: ");
function->PrintName();
PrintF(" at AST id %d]\n", ast_id.ToInt());
}
return NULL;
}
job = thread->FindReadyOSRCandidate(function, ast_id);
}
if (job != NULL) {
if (FLAG_trace_osr) {
PrintF("[OSR - Found ready: ");
function->PrintName();
PrintF(" at AST id %d]\n", ast_id.ToInt());
}
result = Compiler::GetConcurrentlyOptimizedCode(job);
} else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
if (FLAG_trace_osr) {
PrintF("[OSR - Compiling: ");
function->PrintName();
PrintF(" at AST id %d]\n", ast_id.ToInt());
}
MaybeHandle<Code> maybe_result =
Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
if (maybe_result.ToHandle(&result) &&
result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
// Optimization is queued. Return to check later.
return NULL;
}
}
// Revert the patched back edge table, regardless of whether OSR succeeds.
BackEdgeTable::Revert(isolate, *caller_code);
// Check whether we ended up with usable optimized code.
if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
DeoptimizationInputData* data =
DeoptimizationInputData::cast(result->deoptimization_data());
if (data->OsrPcOffset()->value() >= 0) {
DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
if (FLAG_trace_osr) {
PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
ast_id.ToInt(), data->OsrPcOffset()->value());
}
// TODO(titzer): this is a massive hack to make the deopt counts
// match. Fix heuristics for reenabling optimizations!
function->shared()->increment_deopt_count();
// TODO(titzer): Do not install code into the function.
function->ReplaceCode(*result);
return *result;
}
}
// Failed.
if (FLAG_trace_osr) {
PrintF("[OSR - Failed: ");
function->PrintName();
PrintF(" at AST id %d]\n", ast_id.ToInt());
}
if (!function->IsOptimized()) {
function->ReplaceCode(function->shared()->code());
}
return NULL;
}
RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
// First check if this is a real stack overflow.
StackLimitCheck check(isolate);
if (check.JsHasOverflowed()) {
SealHandleScope shs(isolate);
return isolate->StackOverflow();
}
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
return (function->IsOptimized()) ? function->code()
: function->shared()->code();
}
bool CodeGenerationFromStringsAllowed(Isolate* isolate,
Handle<Context> context) {
DCHECK(context->allow_code_gen_from_strings()->IsFalse());
// Check with callback if set.
AllowCodeGenerationFromStringsCallback callback =
isolate->allow_code_gen_callback();
if (callback == NULL) {
// No callback set and code generation disallowed.
return false;
} else {
// Callback set. Let it decide if code generation is allowed.
VMState<EXTERNAL> state(isolate);
return callback(v8::Utils::ToLocal(context));
}
}
RUNTIME_FUNCTION(Runtime_CompileString) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
// Extract native context.
Handle<Context> context(isolate->native_context());
// Check if native context allows code generation from
// strings. Throw an exception if it doesn't.
if (context->allow_code_gen_from_strings()->IsFalse() &&
!CodeGenerationFromStringsAllowed(isolate, context)) {
Handle<Object> error_message =
context->ErrorMessageForCodeGenerationFromStrings();
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewEvalError("code_gen_from_strings",
HandleVector<Object>(&error_message, 1)));
}
// Compile source string in the native context.
ParseRestriction restriction = function_literal_only
? ONLY_SINGLE_FUNCTION_LITERAL
: NO_PARSE_RESTRICTION;
Handle<JSFunction> fun;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, fun,
Compiler::GetFunctionFromEval(source, context, SLOPPY, restriction,
RelocInfo::kNoPosition));
return *fun;
}
static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
Handle<Object> receiver,
StrictMode strict_mode,
int scope_position) {
Handle<Context> context = Handle<Context>(isolate->context());
Handle<Context> native_context = Handle<Context>(context->native_context());
// Check if native context allows code generation from
// strings. Throw an exception if it doesn't.
if (native_context->allow_code_gen_from_strings()->IsFalse() &&
!CodeGenerationFromStringsAllowed(isolate, native_context)) {
Handle<Object> error_message =
native_context->ErrorMessageForCodeGenerationFromStrings();
Handle<Object> error;
MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
"code_gen_from_strings", HandleVector<Object>(&error_message, 1));
if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
return MakePair(isolate->heap()->exception(), NULL);
}
// Deal with a normal eval call with a string argument. Compile it
// and return the compiled function bound in the local context.
static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
Handle<JSFunction> compiled;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, compiled,
Compiler::GetFunctionFromEval(source, context, strict_mode, restriction,
scope_position),
MakePair(isolate->heap()->exception(), NULL));
return MakePair(*compiled, *receiver);
}
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
HandleScope scope(isolate);
DCHECK(args.length() == 5);
Handle<Object> callee = args.at<Object>(0);
// If "eval" didn't refer to the original GlobalEval, it's not a
// direct call to eval.
// (And even if it is, but the first argument isn't a string, just let
// execution default to an indirect call to eval, which will also return
// the first argument without doing anything).
if (*callee != isolate->native_context()->global_eval_fun() ||
!args[1]->IsString()) {
return MakePair(*callee, isolate->heap()->undefined_value());
}
DCHECK(args[3]->IsSmi());
DCHECK(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT);
StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3));
DCHECK(args[4]->IsSmi());
return CompileGlobalEval(isolate, args.at<String>(1), args.at<Object>(2),
strict_mode, args.smi_at(4));
}
}
} // namespace v8::internal

View File

@ -0,0 +1,247 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/assembler.h"
#include "src/codegen.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
#include "third_party/fdlibm/fdlibm.h"
namespace v8 {
namespace internal {
#define RUNTIME_UNARY_MATH(Name, name) \
RUNTIME_FUNCTION(Runtime_Math##Name) { \
HandleScope scope(isolate); \
DCHECK(args.length() == 1); \
isolate->counters()->math_##name()->Increment(); \
CONVERT_DOUBLE_ARG_CHECKED(x, 0); \
return *isolate->factory()->NewHeapNumber(std::name(x)); \
}
RUNTIME_UNARY_MATH(Acos, acos)
RUNTIME_UNARY_MATH(Asin, asin)
RUNTIME_UNARY_MATH(Atan, atan)
RUNTIME_UNARY_MATH(LogRT, log)
#undef RUNTIME_UNARY_MATH
RUNTIME_FUNCTION(Runtime_DoubleHi) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
uint64_t integer = double_to_uint64(x);
integer = (integer >> 32) & 0xFFFFFFFFu;
return *isolate->factory()->NewNumber(static_cast<int32_t>(integer));
}
RUNTIME_FUNCTION(Runtime_DoubleLo) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return *isolate->factory()->NewNumber(
static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
}
RUNTIME_FUNCTION(Runtime_ConstructDouble) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
return *isolate->factory()->NewNumber(uint64_to_double(result));
}
RUNTIME_FUNCTION(Runtime_RemPiO2) {
HandleScope handle_scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Factory* factory = isolate->factory();
double y[2];
int n = fdlibm::rempio2(x, y);
Handle<FixedArray> array = factory->NewFixedArray(3);
Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]);
Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]);
array->set(0, Smi::FromInt(n));
array->set(1, *y0);
array->set(2, *y1);
return *factory->NewJSArrayWithElements(array);
}
static const double kPiDividedBy4 = 0.78539816339744830962;
RUNTIME_FUNCTION(Runtime_MathAtan2) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
isolate->counters()->math_atan2()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
double result;
if (std::isinf(x) && std::isinf(y)) {
// Make sure that the result in case of two infinite arguments
// is a multiple of Pi / 4. The sign of the result is determined
// by the first argument (x) and the sign of the second argument
// determines the multiplier: one or three.
int multiplier = (x < 0) ? -1 : 1;
if (y < 0) multiplier *= 3;
result = multiplier * kPiDividedBy4;
} else {
result = std::atan2(x, y);
}
return *isolate->factory()->NewNumber(result);
}
RUNTIME_FUNCTION(Runtime_MathExpRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
isolate->counters()->math_exp()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
lazily_initialize_fast_exp();
return *isolate->factory()->NewNumber(fast_exp(x));
}
RUNTIME_FUNCTION(Runtime_MathFloorRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
isolate->counters()->math_floor()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return *isolate->factory()->NewNumber(Floor(x));
}
// Slow version of Math.pow. We check for fast paths for special cases.
// Used if VFP3 is not available.
RUNTIME_FUNCTION(Runtime_MathPowSlow) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
isolate->counters()->math_pow()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
// If the second argument is a smi, it is much faster to call the
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
int y = args.smi_at(1);
return *isolate->factory()->NewNumber(power_double_int(x, y));
}
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
double result = power_helper(x, y);
if (std::isnan(result)) return isolate->heap()->nan_value();
return *isolate->factory()->NewNumber(result);
}
// Fast version of Math.pow if we know that y is not an integer and y is not
// -0.5 or 0.5. Used as slow case from full codegen.
RUNTIME_FUNCTION(Runtime_MathPowRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
isolate->counters()->math_pow()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
if (y == 0) {
return Smi::FromInt(1);
} else {
double result = power_double_double(x, y);
if (std::isnan(result)) return isolate->heap()->nan_value();
return *isolate->factory()->NewNumber(result);
}
}
RUNTIME_FUNCTION(Runtime_RoundNumber) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
isolate->counters()->math_round()->Increment();
if (!input->IsHeapNumber()) {
DCHECK(input->IsSmi());
return *input;
}
Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
double value = number->value();
int exponent = number->get_exponent();
int sign = number->get_sign();
if (exponent < -1) {
// Number in range ]-0.5..0.5[. These always round to +/-zero.
if (sign) return isolate->heap()->minus_zero_value();
return Smi::FromInt(0);
}
// We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
// should be rounded to 2^30, which is not smi (for 31-bit smis, similar
// argument holds for 32-bit smis).
if (!sign && exponent < kSmiValueSize - 2) {
return Smi::FromInt(static_cast<int>(value + 0.5));
}
// If the magnitude is big enough, there's no place for fraction part. If we
// try to add 0.5 to this number, 1.0 will be added instead.
if (exponent >= 52) {
return *number;
}
if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
// Do not call NumberFromDouble() to avoid extra checks.
return *isolate->factory()->NewNumber(Floor(value + 0.5));
}
RUNTIME_FUNCTION(Runtime_MathSqrtRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
isolate->counters()->math_sqrt()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return *isolate->factory()->NewNumber(fast_sqrt(x));
}
RUNTIME_FUNCTION(Runtime_MathFround) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
float xf = DoubleToFloat32(x);
return *isolate->factory()->NewNumber(xf);
}
RUNTIME_FUNCTION(RuntimeReference_MathPow) {
SealHandleScope shs(isolate);
return __RT_impl_Runtime_MathPowSlow(args, isolate);
}
RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, obj, 0);
if (!obj->IsHeapNumber()) return isolate->heap()->false_value();
HeapNumber* number = HeapNumber::cast(obj);
return isolate->heap()->ToBoolean(IsMinusZero(number->value()));
}
}
} // namespace v8::internal

View File

@ -0,0 +1,565 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/codegen.h"
#include "src/misc-intrinsics.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
#ifndef _STLP_VENDOR_CSTD
// STLPort doesn't import fpclassify and isless into the std namespace.
using std::fpclassify;
using std::isless;
#endif
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_SMI_ARG_CHECKED(radix, 1);
RUNTIME_ASSERT(2 <= radix && radix <= 36);
// Fast case where the result is a one character string.
if (args[0]->IsSmi()) {
int value = args.smi_at(0);
if (value >= 0 && value < radix) {
// Character array used for conversion.
static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
return *isolate->factory()->LookupSingleCharacterStringFromCode(
kCharTable[value]);
}
}
// Slow case.
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (std::isnan(value)) {
return isolate->heap()->nan_string();
}
if (std::isinf(value)) {
if (value < 0) {
return isolate->heap()->minus_infinity_string();
}
return isolate->heap()->infinity_string();
}
char* str = DoubleToRadixCString(value, radix);
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
RUNTIME_FUNCTION(Runtime_NumberToFixed) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
// See DoubleToFixedCString for these constants:
RUNTIME_ASSERT(f >= 0 && f <= 20);
RUNTIME_ASSERT(!Double(value).IsSpecial());
char* str = DoubleToFixedCString(value, f);
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
RUNTIME_FUNCTION(Runtime_NumberToExponential) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= -1 && f <= 20);
RUNTIME_ASSERT(!Double(value).IsSpecial());
char* str = DoubleToExponentialCString(value, f);
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= 1 && f <= 21);
RUNTIME_ASSERT(!Double(value).IsSpecial());
char* str = DoubleToPrecisionCString(value, f);
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
DeleteArray(str);
return *result;
}
RUNTIME_FUNCTION(Runtime_IsValidSmi) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
return isolate->heap()->ToBoolean(Smi::IsValid(number));
}
static bool AreDigits(const uint8_t* s, int from, int to) {
for (int i = from; i < to; i++) {
if (s[i] < '0' || s[i] > '9') return false;
}
return true;
}
static int ParseDecimalInteger(const uint8_t* s, int from, int to) {
DCHECK(to - from < 10); // Overflow is not possible.
DCHECK(from < to);
int d = s[from] - '0';
for (int i = from + 1; i < to; i++) {
d = 10 * d + (s[i] - '0');
}
return d;
}
RUNTIME_FUNCTION(Runtime_StringToNumber) {
HandleScope handle_scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
subject = String::Flatten(subject);
// Fast case: short integer or some sorts of junk values.
if (subject->IsSeqOneByteString()) {
int len = subject->length();
if (len == 0) return Smi::FromInt(0);
DisallowHeapAllocation no_gc;
uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
bool minus = (data[0] == '-');
int start_pos = (minus ? 1 : 0);
if (start_pos == len) {
return isolate->heap()->nan_value();
} else if (data[start_pos] > '9') {
// Fast check for a junk value. A valid string may start from a
// whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
// or the 'I' character ('Infinity'). All of that have codes not greater
// than '9' except 'I' and &nbsp;.
if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
return isolate->heap()->nan_value();
}
} else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
// The maximal/minimal smi has 10 digits. If the string has less digits
// we know it will fit into the smi-data type.
int d = ParseDecimalInteger(data, start_pos, len);
if (minus) {
if (d == 0) return isolate->heap()->minus_zero_value();
d = -d;
} else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
(len == 1 || data[0] != '0')) {
// String hash is not calculated yet but all the data are present.
// Update the hash field to speed up sequential convertions.
uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
#ifdef DEBUG
subject->Hash(); // Force hash calculation.
DCHECK_EQ(static_cast<int>(subject->hash_field()),
static_cast<int>(hash));
#endif
subject->set_hash_field(hash);
}
return Smi::FromInt(d);
}
}
// Slower case.
int flags = ALLOW_HEX;
if (FLAG_harmony_numeric_literals) {
// The current spec draft has not updated "ToNumber Applied to the String
// Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
flags |= ALLOW_OCTAL | ALLOW_BINARY;
}
return *isolate->factory()->NewNumber(
StringToDouble(isolate->unicode_cache(), *subject, flags));
}
RUNTIME_FUNCTION(Runtime_StringParseInt) {
HandleScope handle_scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
subject = String::Flatten(subject);
double value;
{
DisallowHeapAllocation no_gc;
String::FlatContent flat = subject->GetFlatContent();
// ECMA-262 section 15.1.2.3, empty string is NaN
if (flat.IsOneByte()) {
value =
StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(), radix);
} else {
value = StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix);
}
}
return *isolate->factory()->NewNumber(value);
}
RUNTIME_FUNCTION(Runtime_StringParseFloat) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
subject = String::Flatten(subject);
double value = StringToDouble(isolate->unicode_cache(), *subject,
ALLOW_TRAILING_JUNK, base::OS::nan_value());
return *isolate->factory()->NewNumber(value);
}
RUNTIME_FUNCTION(Runtime_NumberToStringRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
return *isolate->factory()->NumberToString(number);
}
RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
return *isolate->factory()->NumberToString(number, false);
}
RUNTIME_FUNCTION(Runtime_NumberToInteger) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(number, 0);
return *isolate->factory()->NewNumber(DoubleToInteger(number));
}
RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(number, 0);
double double_value = DoubleToInteger(number);
// Map both -0 and +0 to +0.
if (double_value == 0) double_value = 0;
return *isolate->factory()->NewNumber(double_value);
}
RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
return *isolate->factory()->NewNumberFromUint(number);
}
RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(number, 0);
return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
}
// Converts a Number to a Smi, if possible. Returns NaN if the number is not
// a small integer.
RUNTIME_FUNCTION(Runtime_NumberToSmi) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, obj, 0);
if (obj->IsSmi()) {
return obj;
}
if (obj->IsHeapNumber()) {
double value = HeapNumber::cast(obj)->value();
int int_value = FastD2I(value);
if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
return Smi::FromInt(int_value);
}
}
return isolate->heap()->nan_value();
}
RUNTIME_FUNCTION(Runtime_NumberAdd) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return *isolate->factory()->NewNumber(x + y);
}
RUNTIME_FUNCTION(Runtime_NumberSub) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return *isolate->factory()->NewNumber(x - y);
}
RUNTIME_FUNCTION(Runtime_NumberMul) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return *isolate->factory()->NewNumber(x * y);
}
RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return *isolate->factory()->NewNumber(-x);
}
RUNTIME_FUNCTION(Runtime_NumberDiv) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return *isolate->factory()->NewNumber(x / y);
}
RUNTIME_FUNCTION(Runtime_NumberMod) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return *isolate->factory()->NewNumber(modulo(x, y));
}
RUNTIME_FUNCTION(Runtime_NumberImul) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
// We rely on implementation-defined behavior below, but at least not on
// undefined behavior.
CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]);
int32_t product = static_cast<int32_t>(x * y);
return *isolate->factory()->NewNumberFromInt(product);
}
RUNTIME_FUNCTION(Runtime_NumberOr) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromInt(x | y);
}
RUNTIME_FUNCTION(Runtime_NumberAnd) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromInt(x & y);
}
RUNTIME_FUNCTION(Runtime_NumberXor) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromInt(x ^ y);
}
RUNTIME_FUNCTION(Runtime_NumberShl) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
}
RUNTIME_FUNCTION(Runtime_NumberShr) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
}
RUNTIME_FUNCTION(Runtime_NumberSar) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
return *isolate->factory()->NewNumberFromInt(
ArithmeticShiftRight(x, y & 0x1f));
}
RUNTIME_FUNCTION(Runtime_NumberEquals) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
if (x == y) return Smi::FromInt(EQUAL);
Object* result;
if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
result = Smi::FromInt(EQUAL);
} else {
result = Smi::FromInt(NOT_EQUAL);
}
return result;
}
RUNTIME_FUNCTION(Runtime_NumberCompare) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 3);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
if (x == y) return Smi::FromInt(EQUAL);
if (isless(x, y)) return Smi::FromInt(LESS);
return Smi::FromInt(GREATER);
}
// Compare two Smis as if they were converted to strings and then
// compared lexicographically.
RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_SMI_ARG_CHECKED(x_value, 0);
CONVERT_SMI_ARG_CHECKED(y_value, 1);
// If the integers are equal so are the string representations.
if (x_value == y_value) return Smi::FromInt(EQUAL);
// If one of the integers is zero the normal integer order is the
// same as the lexicographic order of the string representations.
if (x_value == 0 || y_value == 0)
return Smi::FromInt(x_value < y_value ? LESS : GREATER);
// If only one of the integers is negative the negative number is
// smallest because the char code of '-' is less than the char code
// of any digit. Otherwise, we make both values positive.
// Use unsigned values otherwise the logic is incorrect for -MIN_INT on
// architectures using 32-bit Smis.
uint32_t x_scaled = x_value;
uint32_t y_scaled = y_value;
if (x_value < 0 || y_value < 0) {
if (y_value >= 0) return Smi::FromInt(LESS);
if (x_value >= 0) return Smi::FromInt(GREATER);
x_scaled = -x_value;
y_scaled = -y_value;
}
static const uint32_t kPowersOf10[] = {
1, 10, 100, 1000,
10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000,
100 * 1000 * 1000, 1000 * 1000 * 1000};
// If the integers have the same number of decimal digits they can be
// compared directly as the numeric order is the same as the
// lexicographic order. If one integer has fewer digits, it is scaled
// by some power of 10 to have the same number of digits as the longer
// integer. If the scaled integers are equal it means the shorter
// integer comes first in the lexicographic order.
// From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
int x_log2 = IntegerLog2(x_scaled);
int x_log10 = ((x_log2 + 1) * 1233) >> 12;
x_log10 -= x_scaled < kPowersOf10[x_log10];
int y_log2 = IntegerLog2(y_scaled);
int y_log10 = ((y_log2 + 1) * 1233) >> 12;
y_log10 -= y_scaled < kPowersOf10[y_log10];
int tie = EQUAL;
if (x_log10 < y_log10) {
// X has fewer digits. We would like to simply scale up X but that
// might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
// be scaled up to 9_000_000_000. So we scale up by the next
// smallest power and scale down Y to drop one digit. It is OK to
// drop one digit from the longer integer since the final digit is
// past the length of the shorter integer.
x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
y_scaled /= 10;
tie = LESS;
} else if (y_log10 < x_log10) {
y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
x_scaled /= 10;
tie = GREATER;
}
if (x_scaled < y_scaled) return Smi::FromInt(LESS);
if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
return Smi::FromInt(tie);
}
RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
SealHandleScope shs(isolate);
return __RT_impl_Runtime_NumberToStringRT(args, isolate);
}
}
} // namespace v8::internal

View File

@ -1182,6 +1182,14 @@ RUNTIME_FUNCTION(Runtime_StringEquals) {
}
RUNTIME_FUNCTION(Runtime_FlattenString) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
return *String::Flatten(str);
}
RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) {
SealHandleScope shs(isolate);
return __RT_impl_Runtime_CharFromCode(args, isolate);

323
src/runtime/runtime-test.cc Normal file
View File

@ -0,0 +1,323 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/deoptimizer.h"
#include "src/full-codegen.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
if (!function->IsOptimized()) return isolate->heap()->undefined_value();
// TODO(turbofan): Deoptimization is not supported yet.
if (function->code()->is_turbofanned() && !FLAG_turbo_deoptimization) {
return isolate->heap()->undefined_value();
}
Deoptimizer::DeoptimizeFunction(*function);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
#if defined(USE_SIMULATOR)
return isolate->heap()->true_value();
#else
return isolate->heap()->false_value();
#endif
}
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
return isolate->heap()->ToBoolean(
isolate->concurrent_recompilation_enabled());
}
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
// The following two assertions are lifted from the DCHECKs inside
// JSFunction::MarkForOptimization().
RUNTIME_ASSERT(!function->shared()->is_generator());
RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
(function->code()->kind() == Code::FUNCTION &&
function->code()->optimizable()));
// If the function is optimized, just return.
if (function->IsOptimized()) return isolate->heap()->undefined_value();
function->MarkForOptimization();
Code* unoptimized = function->shared()->code();
if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) {
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("osr")) && FLAG_use_osr) {
// Start patching from the currently patched loop nesting level.
DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
isolate->runtime_profiler()->AttemptOnStackReplacement(
*function, Code::kMaxLoopNestingMarker);
} else if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
isolate->concurrent_recompilation_enabled()) {
function->MarkForConcurrentOptimization();
}
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
function->shared()->set_optimization_disabled(true);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
if (!isolate->use_crankshaft()) {
return Smi::FromInt(4); // 4 == "never".
}
bool sync_with_compiler_thread = true;
if (args.length() == 2) {
CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
sync_with_compiler_thread = false;
}
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
if (isolate->concurrent_recompilation_enabled() &&
sync_with_compiler_thread) {
while (function->IsInOptimizationQueue()) {
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
base::OS::Sleep(50);
}
}
if (FLAG_always_opt) {
// We may have always opt, but that is more best-effort than a real
// promise, so we still say "no" if it is not optimized.
return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
: Smi::FromInt(2); // 2 == "no".
}
if (FLAG_deopt_every_n_times) {
return Smi::FromInt(6); // 6 == "maybe deopted".
}
if (function->IsOptimized() && function->code()->is_turbofanned()) {
return Smi::FromInt(7); // 7 == "TurboFan compiler".
}
return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
: Smi::FromInt(2); // 2 == "no".
}
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
DCHECK(args.length() == 0);
RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
isolate->optimizing_compiler_thread()->Unblock();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return Smi::FromInt(function->shared()->opt_count());
}
RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
function->shared()->ClearTypeFeedbackInfo();
Code* unoptimized = function->shared()->code();
if (unoptimized->kind() == Code::FUNCTION) {
unoptimized->ClearInlineCaches();
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
isolate->heap()->NotifyContextDisposed();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2 || args.length() == 3);
#ifdef DEBUG
CONVERT_SMI_ARG_CHECKED(interval, 0);
CONVERT_SMI_ARG_CHECKED(timeout, 1);
isolate->heap()->set_allocation_timeout(timeout);
FLAG_gc_interval = interval;
if (args.length() == 3) {
// Enable/disable inline allocation if requested.
CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
if (inline_allocation) {
isolate->heap()->EnableInlineAllocation();
} else {
isolate->heap()->DisableInlineAllocation();
}
}
#endif
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DebugPrint) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
OFStream os(stdout);
#ifdef DEBUG
if (args[0]->IsString()) {
// If we have a string, assume it's a code "marker"
// and print some interesting cpu debugging info.
JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame();
os << "fp = " << frame->fp() << ", sp = " << frame->sp()
<< ", caller_sp = " << frame->caller_sp() << ": ";
} else {
os << "DebugPrint: ";
}
args[0]->Print(os);
if (args[0]->IsHeapObject()) {
os << "\n";
HeapObject::cast(args[0])->map()->Print(os);
}
#else
// ShortPrint is available in release mode. Print is not.
os << Brief(args[0]);
#endif
os << endl;
return args[0]; // return TOS
}
RUNTIME_FUNCTION(Runtime_DebugTrace) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
isolate->PrintStack(stdout);
return isolate->heap()->undefined_value();
}
// This will not allocate (flatten the string), but it may run
// very slowly for very deeply nested ConsStrings. For debugging use only.
RUNTIME_FUNCTION(Runtime_GlobalPrint) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(String, string, 0);
ConsStringIteratorOp op;
StringCharacterStream stream(string, &op);
while (stream.HasMore()) {
uint16_t character = stream.GetNext();
PrintF("%c", character);
}
return string;
}
RUNTIME_FUNCTION(Runtime_SystemBreak) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
base::OS::DebugBreak();
return isolate->heap()->undefined_value();
}
// Sets a v8 flag.
RUNTIME_FUNCTION(Runtime_SetFlags) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(String, arg, 0);
SmartArrayPointer<char> flags =
arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_Abort) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_SMI_ARG_CHECKED(message_id, 0);
const char* message =
GetBailoutReason(static_cast<BailoutReason>(message_id));
base::OS::PrintError("abort: %s\n", message);
isolate->PrintStack(stderr);
base::OS::Abort();
UNREACHABLE();
return NULL;
}
RUNTIME_FUNCTION(Runtime_AbortJS) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
base::OS::PrintError("abort: %s\n", message->ToCString().get());
isolate->PrintStack(stderr);
base::OS::Abort();
UNREACHABLE();
return NULL;
}
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, obj1, 0);
CONVERT_ARG_CHECKED(JSObject, obj2, 1);
return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
}
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
RUNTIME_FUNCTION(Runtime_Has##Name) { \
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
// Properties test sitting with elements tests - not fooling anyone.
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
}
} // namespace v8::internal

View File

@ -0,0 +1,760 @@
// Copyright 2014 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.
#include "src/v8.h"
#include "src/arguments.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
namespace v8 {
namespace internal {
void Runtime::FreeArrayBuffer(Isolate* isolate,
JSArrayBuffer* phantom_array_buffer) {
if (phantom_array_buffer->should_be_freed()) {
DCHECK(phantom_array_buffer->is_external());
free(phantom_array_buffer->backing_store());
}
if (phantom_array_buffer->is_external()) return;
size_t allocated_length =
NumberToSize(isolate, phantom_array_buffer->byte_length());
reinterpret_cast<v8::Isolate*>(isolate)
->AdjustAmountOfExternalAllocatedMemory(
-static_cast<int64_t>(allocated_length));
CHECK(V8::ArrayBufferAllocator() != NULL);
V8::ArrayBufferAllocator()->Free(phantom_array_buffer->backing_store(),
allocated_length);
}
void Runtime::SetupArrayBuffer(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
bool is_external, void* data,
size_t allocated_length) {
DCHECK(array_buffer->GetInternalFieldCount() ==
v8::ArrayBuffer::kInternalFieldCount);
for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
array_buffer->SetInternalField(i, Smi::FromInt(0));
}
array_buffer->set_backing_store(data);
array_buffer->set_flag(Smi::FromInt(0));
array_buffer->set_is_external(is_external);
Handle<Object> byte_length =
isolate->factory()->NewNumberFromSize(allocated_length);
CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
array_buffer->set_byte_length(*byte_length);
array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
isolate->heap()->set_array_buffers_list(*array_buffer);
array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
}
bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
size_t allocated_length,
bool initialize) {
void* data;
CHECK(V8::ArrayBufferAllocator() != NULL);
if (allocated_length != 0) {
if (initialize) {
data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
} else {
data =
V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
}
if (data == NULL) return false;
} else {
data = NULL;
}
SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
reinterpret_cast<v8::Isolate*>(isolate)
->AdjustAmountOfExternalAllocatedMemory(allocated_length);
return true;
}
void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
Isolate* isolate = array_buffer->GetIsolate();
for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
!view_obj->IsUndefined();) {
Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
if (view->IsJSTypedArray()) {
JSTypedArray::cast(*view)->Neuter();
} else if (view->IsJSDataView()) {
JSDataView::cast(*view)->Neuter();
} else {
UNREACHABLE();
}
view_obj = handle(view->weak_next(), isolate);
}
array_buffer->Neuter();
}
RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
if (!holder->byte_length()->IsUndefined()) {
// ArrayBuffer is already initialized; probably a fuzz test.
return *holder;
}
size_t allocated_length = 0;
if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("invalid_array_buffer_length",
HandleVector<Object>(NULL, 0)));
}
if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
allocated_length)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("invalid_array_buffer_length",
HandleVector<Object>(NULL, 0)));
}
return *holder;
}
RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
return holder->byte_length();
}
RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
RUNTIME_ASSERT(!source.is_identical_to(target));
size_t start = 0;
RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
size_t target_length = NumberToSize(isolate, target->byte_length());
if (target_length == 0) return isolate->heap()->undefined_value();
size_t source_byte_length = NumberToSize(isolate, source->byte_length());
RUNTIME_ASSERT(start <= source_byte_length);
RUNTIME_ASSERT(source_byte_length - start >= target_length);
uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
CopyBytes(target_data, source_data + start, target_length);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, object, 0);
return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
}
RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
if (array_buffer->backing_store() == NULL) {
CHECK(Smi::FromInt(0) == array_buffer->byte_length());
return isolate->heap()->undefined_value();
}
DCHECK(!array_buffer->is_external());
void* backing_store = array_buffer->backing_store();
size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
array_buffer->set_is_external(true);
Runtime::NeuterArrayBuffer(array_buffer);
V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
return isolate->heap()->undefined_value();
}
void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
ElementsKind* external_elements_kind,
ElementsKind* fixed_elements_kind,
size_t* element_size) {
switch (arrayId) {
#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
case ARRAY_ID_##TYPE: \
*array_type = kExternal##Type##Array; \
*external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
*fixed_elements_kind = TYPE##_ELEMENTS; \
*element_size = size; \
break;
TYPED_ARRAYS(ARRAY_ID_CASE)
#undef ARRAY_ID_CASE
default:
UNREACHABLE();
}
}
RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 5);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
CONVERT_SMI_ARG_CHECKED(arrayId, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
arrayId <= Runtime::ARRAY_ID_LAST);
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
ElementsKind external_elements_kind =
EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
&fixed_elements_kind, &element_size);
RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
size_t byte_offset = 0;
size_t byte_length = 0;
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
if (maybe_buffer->IsJSArrayBuffer()) {
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
size_t array_buffer_byte_length =
NumberToSize(isolate, buffer->byte_length());
RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
} else {
RUNTIME_ASSERT(maybe_buffer->IsNull());
}
RUNTIME_ASSERT(byte_length % element_size == 0);
size_t length = byte_length / element_size;
if (length > static_cast<unsigned>(Smi::kMaxValue)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("invalid_typed_array_length",
HandleVector<Object>(NULL, 0)));
}
// All checks are done, now we can modify objects.
DCHECK(holder->GetInternalFieldCount() ==
v8::ArrayBufferView::kInternalFieldCount);
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
holder->SetInternalField(i, Smi::FromInt(0));
}
Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
holder->set_length(*length_obj);
holder->set_byte_offset(*byte_offset_object);
holder->set_byte_length(*byte_length_object);
if (!maybe_buffer->IsNull()) {
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
holder->set_buffer(*buffer);
holder->set_weak_next(buffer->weak_first_view());
buffer->set_weak_first_view(*holder);
Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
static_cast<int>(length), array_type,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
Handle<Map> map =
JSObject::GetElementsTransitionMap(holder, external_elements_kind);
JSObject::SetMapAndElements(holder, map, elements);
DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
} else {
holder->set_buffer(Smi::FromInt(0));
holder->set_weak_next(isolate->heap()->undefined_value());
Handle<FixedTypedArrayBase> elements =
isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
array_type);
holder->set_elements(*elements);
}
return isolate->heap()->undefined_value();
}
// Initializes a typed array from an array-like object.
// If an array-like object happens to be a typed array of the same type,
// initializes backing store using memove.
//
// Returns true if backing store was initialized or false otherwise.
RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
CONVERT_SMI_ARG_CHECKED(arrayId, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
arrayId <= Runtime::ARRAY_ID_LAST);
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
ElementsKind external_elements_kind =
EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
&fixed_elements_kind, &element_size);
RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
if (source->IsJSTypedArray() &&
JSTypedArray::cast(*source)->type() == array_type) {
length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
}
size_t length = 0;
RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
(length > (kMaxInt / element_size))) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("invalid_typed_array_length",
HandleVector<Object>(NULL, 0)));
}
size_t byte_length = length * element_size;
DCHECK(holder->GetInternalFieldCount() ==
v8::ArrayBufferView::kInternalFieldCount);
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
holder->SetInternalField(i, Smi::FromInt(0));
}
// NOTE: not initializing backing store.
// We assume that the caller of this function will initialize holder
// with the loop
// for(i = 0; i < length; i++) { holder[i] = source[i]; }
// We assume that the caller of this function is always a typed array
// constructor.
// If source is a typed array, this loop will always run to completion,
// so we are sure that the backing store will be initialized.
// Otherwise, the indexing operation might throw, so the loop will not
// run to completion and the typed array might remain partly initialized.
// However we further assume that the caller of this function is a typed array
// constructor, and the exception will propagate out of the constructor,
// therefore uninitialized memory will not be accessible by a user program.
//
// TODO(dslomov): revise this once we support subclassing.
if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
false)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("invalid_array_buffer_length",
HandleVector<Object>(NULL, 0)));
}
holder->set_buffer(*buffer);
holder->set_byte_offset(Smi::FromInt(0));
Handle<Object> byte_length_obj(
isolate->factory()->NewNumberFromSize(byte_length));
holder->set_byte_length(*byte_length_obj);
holder->set_length(*length_obj);
holder->set_weak_next(buffer->weak_first_view());
buffer->set_weak_first_view(*holder);
Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
static_cast<int>(length), array_type,
static_cast<uint8_t*>(buffer->backing_store()));
Handle<Map> map =
JSObject::GetElementsTransitionMap(holder, external_elements_kind);
JSObject::SetMapAndElements(holder, map, elements);
if (source->IsJSTypedArray()) {
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
if (typed_array->type() == holder->type()) {
uint8_t* backing_store =
static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
size_t source_byte_offset =
NumberToSize(isolate, typed_array->byte_offset());
memcpy(buffer->backing_store(), backing_store + source_byte_offset,
byte_length);
return isolate->heap()->true_value();
}
}
return isolate->heap()->false_value();
}
#define BUFFER_VIEW_GETTER(Type, getter, accessor) \
RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
HandleScope scope(isolate); \
DCHECK(args.length() == 1); \
CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
return holder->accessor(); \
}
BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
BUFFER_VIEW_GETTER(TypedArray, Length, length)
BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
#undef BUFFER_VIEW_GETTER
RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
return *holder->GetBuffer();
}
// Return codes for Runtime_TypedArraySetFastCases.
// Should be synchronized with typedarray.js natives.
enum TypedArraySetResultCodes {
// Set from typed array of the same type.
// This is processed by TypedArraySetFastCases
TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
// Set from typed array of the different type, overlapping in memory.
TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
// Set from typed array of the different type, non-overlapping.
TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
// Set from non-typed array.
TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
};
RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
if (!args[0]->IsJSTypedArray()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
}
if (!args[1]->IsJSTypedArray())
return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
size_t offset = 0;
RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
size_t target_length = NumberToSize(isolate, target->length());
size_t source_length = NumberToSize(isolate, source->length());
size_t target_byte_length = NumberToSize(isolate, target->byte_length());
size_t source_byte_length = NumberToSize(isolate, source->byte_length());
if (offset > target_length || offset + source_length > target_length ||
offset + source_length < offset) { // overflow
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError("typed_array_set_source_too_large",
HandleVector<Object>(NULL, 0)));
}
size_t target_offset = NumberToSize(isolate, target->byte_offset());
size_t source_offset = NumberToSize(isolate, source->byte_offset());
uint8_t* target_base =
static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
target_offset;
uint8_t* source_base =
static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
source_offset;
// Typed arrays of the same type: use memmove.
if (target->type() == source->type()) {
memmove(target_base + offset * target->element_size(), source_base,
source_byte_length);
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
}
// Typed arrays of different types over the same backing store
if ((source_base <= target_base &&
source_base + source_byte_length > target_base) ||
(target_base <= source_base &&
target_base + target_byte_length > source_base)) {
// We do not support overlapping ArrayBuffers
DCHECK(target->GetBuffer()->backing_store() ==
source->GetBuffer()->backing_store());
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
} else { // Non-overlapping typed arrays
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
}
}
RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
DCHECK(args.length() == 0);
DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
FixedTypedArrayBase::kDataOffset);
return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
}
RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
DCHECK(holder->GetInternalFieldCount() ==
v8::ArrayBufferView::kInternalFieldCount);
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
holder->SetInternalField(i, Smi::FromInt(0));
}
size_t buffer_length = 0;
size_t offset = 0;
size_t length = 0;
RUNTIME_ASSERT(
TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
// TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
// Entire range [offset, offset + length] must be in bounds.
RUNTIME_ASSERT(offset <= buffer_length);
RUNTIME_ASSERT(offset + length <= buffer_length);
// No overflow.
RUNTIME_ASSERT(offset + length >= offset);
holder->set_buffer(*buffer);
holder->set_byte_offset(*byte_offset);
holder->set_byte_length(*byte_length);
holder->set_weak_next(buffer->weak_first_view());
buffer->set_weak_first_view(*holder);
return isolate->heap()->undefined_value();
}
inline static bool NeedToFlipBytes(bool is_little_endian) {
#ifdef V8_TARGET_LITTLE_ENDIAN
return !is_little_endian;
#else
return is_little_endian;
#endif
}
template <int n>
inline void CopyBytes(uint8_t* target, uint8_t* source) {
for (int i = 0; i < n; i++) {
*(target++) = *(source++);
}
}
template <int n>
inline void FlipBytes(uint8_t* target, uint8_t* source) {
source = source + (n - 1);
for (int i = 0; i < n; i++) {
*(target++) = *(source--);
}
}
template <typename T>
inline static bool DataViewGetValue(Isolate* isolate,
Handle<JSDataView> data_view,
Handle<Object> byte_offset_obj,
bool is_little_endian, T* result) {
size_t byte_offset = 0;
if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
return false;
}
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
size_t data_view_byte_offset =
NumberToSize(isolate, data_view->byte_offset());
size_t data_view_byte_length =
NumberToSize(isolate, data_view->byte_length());
if (byte_offset + sizeof(T) > data_view_byte_length ||
byte_offset + sizeof(T) < byte_offset) { // overflow
return false;
}
union Value {
T data;
uint8_t bytes[sizeof(T)];
};
Value value;
size_t buffer_offset = data_view_byte_offset + byte_offset;
DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
buffer_offset + sizeof(T));
uint8_t* source =
static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
if (NeedToFlipBytes(is_little_endian)) {
FlipBytes<sizeof(T)>(value.bytes, source);
} else {
CopyBytes<sizeof(T)>(value.bytes, source);
}
*result = value.data;
return true;
}
template <typename T>
static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
Handle<Object> byte_offset_obj,
bool is_little_endian, T data) {
size_t byte_offset = 0;
if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
return false;
}
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
size_t data_view_byte_offset =
NumberToSize(isolate, data_view->byte_offset());
size_t data_view_byte_length =
NumberToSize(isolate, data_view->byte_length());
if (byte_offset + sizeof(T) > data_view_byte_length ||
byte_offset + sizeof(T) < byte_offset) { // overflow
return false;
}
union Value {
T data;
uint8_t bytes[sizeof(T)];
};
Value value;
value.data = data;
size_t buffer_offset = data_view_byte_offset + byte_offset;
DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
buffer_offset + sizeof(T));
uint8_t* target =
static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
if (NeedToFlipBytes(is_little_endian)) {
FlipBytes<sizeof(T)>(target, value.bytes);
} else {
CopyBytes<sizeof(T)>(target, value.bytes);
}
return true;
}
#define DATA_VIEW_GETTER(TypeName, Type, Converter) \
RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \
HandleScope scope(isolate); \
DCHECK(args.length() == 3); \
CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
Type result; \
if (DataViewGetValue(isolate, holder, offset, is_little_endian, \
&result)) { \
return *isolate->factory()->Converter(result); \
} else { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewRangeError("invalid_data_view_accessor_offset", \
HandleVector<Object>(NULL, 0))); \
} \
}
DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
DATA_VIEW_GETTER(Float32, float, NewNumber)
DATA_VIEW_GETTER(Float64, double, NewNumber)
#undef DATA_VIEW_GETTER
template <typename T>
static T DataViewConvertValue(double value);
template <>
int8_t DataViewConvertValue<int8_t>(double value) {
return static_cast<int8_t>(DoubleToInt32(value));
}
template <>
int16_t DataViewConvertValue<int16_t>(double value) {
return static_cast<int16_t>(DoubleToInt32(value));
}
template <>
int32_t DataViewConvertValue<int32_t>(double value) {
return DoubleToInt32(value);
}
template <>
uint8_t DataViewConvertValue<uint8_t>(double value) {
return static_cast<uint8_t>(DoubleToUint32(value));
}
template <>
uint16_t DataViewConvertValue<uint16_t>(double value) {
return static_cast<uint16_t>(DoubleToUint32(value));
}
template <>
uint32_t DataViewConvertValue<uint32_t>(double value) {
return DoubleToUint32(value);
}
template <>
float DataViewConvertValue<float>(double value) {
return static_cast<float>(value);
}
template <>
double DataViewConvertValue<double>(double value) {
return value;
}
#define DATA_VIEW_SETTER(TypeName, Type) \
RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \
HandleScope scope(isolate); \
DCHECK(args.length() == 4); \
CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \
CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
Type v = DataViewConvertValue<Type>(value->Number()); \
if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
return isolate->heap()->undefined_value(); \
} else { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewRangeError("invalid_data_view_accessor_offset", \
HandleVector<Object>(NULL, 0))); \
} \
}
DATA_VIEW_SETTER(Uint8, uint8_t)
DATA_VIEW_SETTER(Int8, int8_t)
DATA_VIEW_SETTER(Uint16, uint16_t)
DATA_VIEW_SETTER(Int16, int16_t)
DATA_VIEW_SETTER(Uint32, uint32_t)
DATA_VIEW_SETTER(Int32, int32_t)
DATA_VIEW_SETTER(Float32, float)
DATA_VIEW_SETTER(Float64, double)
#undef DATA_VIEW_SETTER
}
} // namespace v8::internal

File diff suppressed because it is too large Load Diff

View File

@ -735,10 +735,16 @@
'../../src/rewriter.h',
'../../src/runtime-profiler.cc',
'../../src/runtime-profiler.h',
'../../src/runtime/runtime-collections.cc',
'../../src/runtime/runtime-compiler.cc',
'../../src/runtime/runtime-i18n.cc',
'../../src/runtime/runtime-json.cc',
'../../src/runtime/runtime-maths.cc',
'../../src/runtime/runtime-numbers.cc',
'../../src/runtime/runtime-regexp.cc',
'../../src/runtime/runtime-strings.cc',
'../../src/runtime/runtime-test.cc',
'../../src/runtime/runtime-typedarray.cc',
'../../src/runtime/runtime-uri.cc',
'../../src/runtime/runtime-utils.h',
'../../src/runtime/runtime.cc',