blob: 32246f34872b7ae863e99b2e1be302cd853ff4ab [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
35#include "compiler.h"
36#include "cpu.h"
37#include "dateparser.h"
38#include "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 bool* is_result_from_cache) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000105 if (FLAG_canonicalize_object_literal_maps) {
106 // First find prefix of consecutive symbol keys.
107 int number_of_properties = constant_properties->length()/2;
108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000116 if ((number_of_symbol_keys == number_of_properties) &&
117 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000123 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000127 *is_result_from_cache = false;
ager@chromium.org236ad962008-09-25 09:45:57 +0000128 return Handle<Map>(context->object_function()->initial_map());
129}
130
131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
133 HandleScope scope;
134 ASSERT(args.length() == 3);
135 // Copy the arguments.
136 Handle<FixedArray> literals = args.at<FixedArray>(0);
137 int literals_index = Smi::cast(args[1])->value();
138 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000139
140 // Get the global context from the literals array. This is the
141 // context in which the function was created and we use the object
142 // function from this context to create the object literal. We do
143 // not use the object function from the current global context
144 // because this might be the object function from another context
145 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000146 Handle<Context> context =
147 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
148
149 bool is_result_from_cache;
150 Handle<Map> map = ComputeObjectLiteralMap(context,
151 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000152 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153
ager@chromium.org236ad962008-09-25 09:45:57 +0000154 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 { // Add the constant propeties to the boilerplate.
156 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000157 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
158 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 for (int index = 0; index < length; index +=2) {
160 Handle<Object> key(constant_properties->get(index+0));
161 Handle<Object> value(constant_properties->get(index+1));
162 uint32_t element_index = 0;
163 if (key->IsSymbol()) {
164 // If key is a symbol it is not an array element.
165 Handle<String> name(String::cast(*key));
166 ASSERT(!name->AsArrayIndex(&element_index));
167 SetProperty(boilerplate, name, value, NONE);
168 } else if (Array::IndexFromObject(*key, &element_index)) {
169 // Array index (uint32).
170 SetElement(boilerplate, element_index, value);
171 } else {
172 // Non-uint32 number.
173 ASSERT(key->IsNumber());
174 double num = key->Number();
175 char arr[100];
176 Vector<char> buffer(arr, ARRAY_SIZE(arr));
177 const char* str = DoubleToCString(num, buffer);
178 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
179 SetProperty(boilerplate, name, value, NONE);
180 }
181 }
182 }
183
184 // Update the functions literal and return the boilerplate.
185 literals->set(literals_index, *boilerplate);
186
187 return *boilerplate;
188}
189
190
191static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192 // Takes a FixedArray of elements containing the literal elements of
193 // the array literal and produces JSArray with those elements.
194 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000195 // which contains the context from which to get the Array function
196 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197 ASSERT(args.length() == 2);
198 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000199 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000200 JSFunction* constructor =
201 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202 // Create the JSArray.
203 Object* object = Heap::AllocateJSObject(constructor);
204 if (object->IsFailure()) return object;
205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206 // Copy the elements.
207 Object* content = elements->Copy();
208 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209
210 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 return object;
213}
214
215
216static Object* Runtime_ClassOf(Arguments args) {
217 NoHandleAllocation ha;
218 ASSERT(args.length() == 1);
219 Object* obj = args[0];
220 if (!obj->IsJSObject()) return Heap::null_value();
221 return JSObject::cast(obj)->class_name();
222}
223
ager@chromium.org7c537e22008-10-16 08:43:32 +0000224
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000225static Object* Runtime_HasStringClass(Arguments args) {
226 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000227}
228
229
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000230static Object* Runtime_HasDateClass(Arguments args) {
231 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000232}
233
234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000235static Object* Runtime_HasArrayClass(Arguments args) {
236 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
237}
238
239
240static Object* Runtime_HasFunctionClass(Arguments args) {
241 return Heap::ToBoolean(
242 args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
243}
244
245
246static Object* Runtime_HasNumberClass(Arguments args) {
247 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
248}
249
250
251static Object* Runtime_HasBooleanClass(Arguments args) {
252 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
253}
254
255
256static Object* Runtime_HasArgumentsClass(Arguments args) {
257 return Heap::ToBoolean(
258 args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
259}
260
261
262static Object* Runtime_HasRegExpClass(Arguments args) {
263 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000264}
265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266
267static Object* Runtime_IsInPrototypeChain(Arguments args) {
268 NoHandleAllocation ha;
269 ASSERT(args.length() == 2);
270 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
271 Object* O = args[0];
272 Object* V = args[1];
273 while (true) {
274 Object* prototype = V->GetPrototype();
275 if (prototype->IsNull()) return Heap::false_value();
276 if (O == prototype) return Heap::true_value();
277 V = prototype;
278 }
279}
280
281
282static Object* Runtime_IsConstructCall(Arguments args) {
283 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000284 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285 JavaScriptFrameIterator it;
286 return Heap::ToBoolean(it.frame()->IsConstructor());
287}
288
289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290static Object* Runtime_RegExpCompile(Arguments args) {
291 HandleScope scope; // create a new handle scope
292 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
294 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 CONVERT_CHECKED(String, raw_pattern, args[1]);
296 Handle<String> pattern(raw_pattern);
297 CONVERT_CHECKED(String, raw_flags, args[2]);
298 Handle<String> flags(raw_flags);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 return *RegExpImpl::Compile(re, pattern, flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300}
301
302
303static Object* Runtime_CreateApiFunction(Arguments args) {
304 HandleScope scope;
305 ASSERT(args.length() == 1);
306 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
307 Handle<FunctionTemplateInfo> data(raw_data);
308 return *Factory::CreateApiFunction(data);
309}
310
311
312static Object* Runtime_IsTemplate(Arguments args) {
313 ASSERT(args.length() == 1);
314 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000315 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 return Heap::ToBoolean(result);
317}
318
319
320static Object* Runtime_GetTemplateField(Arguments args) {
321 ASSERT(args.length() == 2);
322 CONVERT_CHECKED(HeapObject, templ, args[0]);
323 RUNTIME_ASSERT(templ->IsStruct());
324 CONVERT_CHECKED(Smi, field, args[1]);
325 return HeapObject::GetHeapObjectField(templ, field->value());
326}
327
328
329static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
330 HandleScope scope;
331 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
332 Handle<Object> args[2] = { type_handle, name };
333 Handle<Object> error =
334 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
335 return Top::Throw(*error);
336}
337
338
339static Object* Runtime_DeclareGlobals(Arguments args) {
340 HandleScope scope;
341 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
342
343 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
344 Handle<Context> context = args.at<Context>(1);
345 bool is_eval = Smi::cast(args[2])->value() == 1;
346
347 // Compute the property attributes. According to ECMA-262, section
348 // 13, page 71, the property must be read-only and
349 // non-deletable. However, neither SpiderMonkey nor KJS creates the
350 // property as read-only, so we don't either.
351 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
352
353 // Only optimize the object if we intend to add more than 5 properties.
354 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
355
356 // Traverse the name/value pairs and set the properties.
357 int length = pairs->length();
358 for (int i = 0; i < length; i += 2) {
359 HandleScope scope;
360 Handle<String> name(String::cast(pairs->get(i)));
361 Handle<Object> value(pairs->get(i + 1));
362
363 // We have to declare a global const property. To capture we only
364 // assign to it when evaluating the assignment for "const x =
365 // <expr>" the initial value is the hole.
366 bool is_const_property = value->IsTheHole();
367
368 if (value->IsUndefined() || is_const_property) {
369 // Lookup the property in the global object, and don't set the
370 // value of the variable if the property is already there.
371 LookupResult lookup;
372 global->Lookup(*name, &lookup);
373 if (lookup.IsProperty()) {
374 // Determine if the property is local by comparing the holder
375 // against the global object. The information will be used to
376 // avoid throwing re-declaration errors when declaring
377 // variables or constants that exist in the prototype chain.
378 bool is_local = (*global == lookup.holder());
379 // Get the property attributes and determine if the property is
380 // read-only.
381 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
382 bool is_read_only = (attributes & READ_ONLY) != 0;
383 if (lookup.type() == INTERCEPTOR) {
384 // If the interceptor says the property is there, we
385 // just return undefined without overwriting the property.
386 // Otherwise, we continue to setting the property.
387 if (attributes != ABSENT) {
388 // Check if the existing property conflicts with regards to const.
389 if (is_local && (is_read_only || is_const_property)) {
390 const char* type = (is_read_only) ? "const" : "var";
391 return ThrowRedeclarationError(type, name);
392 };
393 // The property already exists without conflicting: Go to
394 // the next declaration.
395 continue;
396 }
397 // Fall-through and introduce the absent property by using
398 // SetProperty.
399 } else {
400 if (is_local && (is_read_only || is_const_property)) {
401 const char* type = (is_read_only) ? "const" : "var";
402 return ThrowRedeclarationError(type, name);
403 }
404 // The property already exists without conflicting: Go to
405 // the next declaration.
406 continue;
407 }
408 }
409 } else {
410 // Copy the function and update its context. Use it as value.
411 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
412 Handle<JSFunction> function =
413 Factory::NewFunctionFromBoilerplate(boilerplate, context);
414 value = function;
415 }
416
417 LookupResult lookup;
418 global->LocalLookup(*name, &lookup);
419
420 PropertyAttributes attributes = is_const_property
421 ? static_cast<PropertyAttributes>(base | READ_ONLY)
422 : base;
423
424 if (lookup.IsProperty()) {
425 // There's a local property that we need to overwrite because
426 // we're either declaring a function or there's an interceptor
427 // that claims the property is absent.
428
429 // Check for conflicting re-declarations. We cannot have
430 // conflicting types in case of intercepted properties because
431 // they are absent.
432 if (lookup.type() != INTERCEPTOR &&
433 (lookup.IsReadOnly() || is_const_property)) {
434 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
435 return ThrowRedeclarationError(type, name);
436 }
437 SetProperty(global, name, value, attributes);
438 } else {
439 // If a property with this name does not already exist on the
440 // global object add the property locally. We take special
441 // precautions to always add it as a local property even in case
442 // of callbacks in the prototype chain (this rules out using
443 // SetProperty). Also, we must use the handle-based version to
444 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000445 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 }
447 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 return Heap::undefined_value();
450}
451
452
453static Object* Runtime_DeclareContextSlot(Arguments args) {
454 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000455 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456
ager@chromium.org7c537e22008-10-16 08:43:32 +0000457 CONVERT_ARG_CHECKED(Context, context, 0);
458 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000460 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000462 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463
464 // Declarations are always done in the function context.
465 context = Handle<Context>(context->fcontext());
466
467 int index;
468 PropertyAttributes attributes;
469 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000470 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 context->Lookup(name, flags, &index, &attributes);
472
473 if (attributes != ABSENT) {
474 // The name was declared before; check for conflicting
475 // re-declarations: This is similar to the code in parser.cc in
476 // the AstBuildingParser::Declare function.
477 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
478 // Functions are not read-only.
479 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
480 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
481 return ThrowRedeclarationError(type, name);
482 }
483
484 // Initialize it if necessary.
485 if (*initial_value != NULL) {
486 if (index >= 0) {
487 // The variable or constant context slot should always be in
488 // the function context; not in any outer context nor in the
489 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000490 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491 if (((attributes & READ_ONLY) == 0) ||
492 context->get(index)->IsTheHole()) {
493 context->set(index, *initial_value);
494 }
495 } else {
496 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000497 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498 SetProperty(context_ext, name, initial_value, mode);
499 }
500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000503 // The property is not in the function context. It needs to be
504 // "declared" in the function context's extension context, or in the
505 // global context.
506 Handle<JSObject> context_ext;
507 if (context->extension() != NULL) {
508 // The function context's extension context exists - use it.
509 context_ext = Handle<JSObject>(context->extension());
510 } else {
511 // The function context's extension context does not exists - allocate
512 // it.
513 context_ext = Factory::NewJSObject(Top::context_extension_function());
514 // And store it in the extension slot.
515 context->set_extension(*context_ext);
516 }
517 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518
ager@chromium.org7c537e22008-10-16 08:43:32 +0000519 // Declare the property by setting it to the initial value if provided,
520 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
521 // constant declarations).
522 ASSERT(!context_ext->HasLocalProperty(*name));
523 Handle<Object> value(Heap::undefined_value());
524 if (*initial_value != NULL) value = initial_value;
525 SetProperty(context_ext, name, value, mode);
526 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
527 }
528
529 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530}
531
532
533static Object* Runtime_InitializeVarGlobal(Arguments args) {
534 NoHandleAllocation nha;
535
536 // Determine if we need to assign to the variable if it already
537 // exists (based on the number of arguments).
538 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
539 bool assign = args.length() == 2;
540
541 CONVERT_ARG_CHECKED(String, name, 0);
542 GlobalObject* global = Top::context()->global();
543
544 // According to ECMA-262, section 12.2, page 62, the property must
545 // not be deletable.
546 PropertyAttributes attributes = DONT_DELETE;
547
548 // Lookup the property locally in the global object. If it isn't
549 // there, we add the property and take special precautions to always
550 // add it as a local property even in case of callbacks in the
551 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553 LookupResult lookup;
554 global->LocalLookup(*name, &lookup);
555 if (!lookup.IsProperty()) {
556 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000557 return global->IgnoreAttributesAndSetLocalProperty(*name,
558 value,
559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 }
561
562 // Determine if this is a redeclaration of something read-only.
563 if (lookup.IsReadOnly()) {
564 return ThrowRedeclarationError("const", name);
565 }
566
567 // Determine if this is a redeclaration of an intercepted read-only
568 // property and figure out if the property exists at all.
569 bool found = true;
570 PropertyType type = lookup.type();
571 if (type == INTERCEPTOR) {
572 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
573 if (intercepted == ABSENT) {
574 // The interceptor claims the property isn't there. We need to
575 // make sure to introduce it.
576 found = false;
577 } else if ((intercepted & READ_ONLY) != 0) {
578 // The property is present, but read-only. Since we're trying to
579 // overwrite it with a variable declaration we must throw a
580 // re-declaration error.
581 return ThrowRedeclarationError("const", name);
582 }
583 // Restore global object from context (in case of GC).
584 global = Top::context()->global();
585 }
586
587 if (found && !assign) {
588 // The global property is there and we're not assigning any value
589 // to it. Just return.
590 return Heap::undefined_value();
591 }
592
593 // Assign the value (or undefined) to the property.
594 Object* value = (assign) ? args[1] : Heap::undefined_value();
595 return global->SetProperty(&lookup, *name, value, attributes);
596}
597
598
599static Object* Runtime_InitializeConstGlobal(Arguments args) {
600 // All constants are declared with an initial value. The name
601 // of the constant is the first argument and the initial value
602 // is the second.
603 RUNTIME_ASSERT(args.length() == 2);
604 CONVERT_ARG_CHECKED(String, name, 0);
605 Handle<Object> value = args.at<Object>(1);
606
607 // Get the current global object from top.
608 GlobalObject* global = Top::context()->global();
609
610 // According to ECMA-262, section 12.2, page 62, the property must
611 // not be deletable. Since it's a const, it must be READ_ONLY too.
612 PropertyAttributes attributes =
613 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
614
615 // Lookup the property locally in the global object. If it isn't
616 // there, we add the property and take special precautions to always
617 // add it as a local property even in case of callbacks in the
618 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000619 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 LookupResult lookup;
621 global->LocalLookup(*name, &lookup);
622 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000623 return global->IgnoreAttributesAndSetLocalProperty(*name,
624 *value,
625 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 }
627
628 // Determine if this is a redeclaration of something not
629 // read-only. In case the result is hidden behind an interceptor we
630 // need to ask it for the property attributes.
631 if (!lookup.IsReadOnly()) {
632 if (lookup.type() != INTERCEPTOR) {
633 return ThrowRedeclarationError("var", name);
634 }
635
636 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
637
638 // Throw re-declaration error if the intercepted property is present
639 // but not read-only.
640 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
641 return ThrowRedeclarationError("var", name);
642 }
643
644 // Restore global object from context (in case of GC) and continue
645 // with setting the value because the property is either absent or
646 // read-only. We also have to do redo the lookup.
647 global = Top::context()->global();
648
649 // BUG 1213579: Handle the case where we have to set a read-only
650 // property through an interceptor and only do it if it's
651 // uninitialized, e.g. the hole. Nirk...
652 global->SetProperty(*name, *value, attributes);
653 return *value;
654 }
655
656 // Set the value, but only we're assigning the initial value to a
657 // constant. For now, we determine this by checking if the
658 // current value is the hole.
659 PropertyType type = lookup.type();
660 if (type == FIELD) {
661 FixedArray* properties = global->properties();
662 int index = lookup.GetFieldIndex();
663 if (properties->get(index)->IsTheHole()) {
664 properties->set(index, *value);
665 }
666 } else if (type == NORMAL) {
667 Dictionary* dictionary = global->property_dictionary();
668 int entry = lookup.GetDictionaryEntry();
669 if (dictionary->ValueAt(entry)->IsTheHole()) {
670 dictionary->ValueAtPut(entry, *value);
671 }
672 } else {
673 // Ignore re-initialization of constants that have already been
674 // assigned a function value.
675 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
676 }
677
678 // Use the set value as the result of the operation.
679 return *value;
680}
681
682
683static Object* Runtime_InitializeConstContextSlot(Arguments args) {
684 HandleScope scope;
685 ASSERT(args.length() == 3);
686
687 Handle<Object> value(args[0]);
688 ASSERT(!value->IsTheHole());
689 CONVERT_ARG_CHECKED(Context, context, 1);
690 Handle<String> name(String::cast(args[2]));
691
692 // Initializations are always done in the function context.
693 context = Handle<Context>(context->fcontext());
694
695 int index;
696 PropertyAttributes attributes;
697 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000698 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699 context->Lookup(name, flags, &index, &attributes);
700
701 // The property should always be present. It is always declared
702 // before being initialized through DeclareContextSlot.
703 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
704
705 // If the slot is in the context, we set it but only if it hasn't
706 // been set before.
707 if (index >= 0) {
708 // The constant context slot should always be in the function
709 // context; not in any outer context nor in the arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000710 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711 if (context->get(index)->IsTheHole()) {
712 context->set(index, *value);
713 }
714 return *value;
715 }
716
717 // Otherwise, the slot must be in a JS object extension.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000718 Handle<JSObject> context_ext(JSObject::cast(*holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719
720 // We must initialize the value only if it wasn't initialized
721 // before, e.g. for const declarations in a loop. The property has
722 // the hole value if it wasn't initialized yet. NOTE: We cannot use
723 // GetProperty() to get the current value as it 'unholes' the value.
724 LookupResult lookup;
725 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
726 ASSERT(lookup.IsProperty()); // the property was declared
727 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
728
729 PropertyType type = lookup.type();
730 if (type == FIELD) {
731 FixedArray* properties = context_ext->properties();
732 int index = lookup.GetFieldIndex();
733 if (properties->get(index)->IsTheHole()) {
734 properties->set(index, *value);
735 }
736 } else if (type == NORMAL) {
737 Dictionary* dictionary = context_ext->property_dictionary();
738 int entry = lookup.GetDictionaryEntry();
739 if (dictionary->ValueAt(entry)->IsTheHole()) {
740 dictionary->ValueAtPut(entry, *value);
741 }
742 } else {
743 // We should not reach here. Any real, named property should be
744 // either a field or a dictionary slot.
745 UNREACHABLE();
746 }
747 return *value;
748}
749
750
751static Object* Runtime_RegExpExec(Arguments args) {
752 HandleScope scope;
753 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000754 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
755 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756 CONVERT_CHECKED(String, raw_subject, args[1]);
757 Handle<String> subject(raw_subject);
758 Handle<Object> index(args[2]);
759 ASSERT(index->IsNumber());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000760 return *RegExpImpl::Exec(regexp, subject, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761}
762
763
764static Object* Runtime_RegExpExecGlobal(Arguments args) {
765 HandleScope scope;
766 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000767 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
768 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 CONVERT_CHECKED(String, raw_subject, args[1]);
770 Handle<String> subject(raw_subject);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000771 return *RegExpImpl::ExecGlobal(regexp, subject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772}
773
774
775static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
776 HandleScope scope;
777 ASSERT(args.length() == 4);
778 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
779 int index = Smi::cast(args[1])->value();
780 Handle<String> pattern = args.at<String>(2);
781 Handle<String> flags = args.at<String>(3);
782
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000783 // Get the RegExp function from the context in the literals array.
784 // This is the RegExp function from the context in which the
785 // function was created. We do not use the RegExp function from the
786 // current global context because this might be the RegExp function
787 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000788 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000789 Handle<JSFunction>(
790 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 // Compute the regular expression literal.
792 bool has_pending_exception;
793 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
795 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796 if (has_pending_exception) {
797 ASSERT(Top::has_pending_exception());
798 return Failure::Exception();
799 }
800 literals->set(index, *regexp);
801 return *regexp;
802}
803
804
805static Object* Runtime_FunctionGetName(Arguments args) {
806 NoHandleAllocation ha;
807 ASSERT(args.length() == 1);
808
809 CONVERT_CHECKED(JSFunction, f, args[0]);
810 return f->shared()->name();
811}
812
813
ager@chromium.org236ad962008-09-25 09:45:57 +0000814static Object* Runtime_FunctionSetName(Arguments args) {
815 NoHandleAllocation ha;
816 ASSERT(args.length() == 2);
817
818 CONVERT_CHECKED(JSFunction, f, args[0]);
819 CONVERT_CHECKED(String, name, args[1]);
820 f->shared()->set_name(name);
821 return Heap::undefined_value();
822}
823
824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825static Object* Runtime_FunctionGetScript(Arguments args) {
826 HandleScope scope;
827 ASSERT(args.length() == 1);
828
829 CONVERT_CHECKED(JSFunction, fun, args[0]);
830 Handle<Object> script = Handle<Object>(fun->shared()->script());
831 if (!script->IsScript()) return Heap::undefined_value();
832
833 return *GetScriptWrapper(Handle<Script>::cast(script));
834}
835
836
837static Object* Runtime_FunctionGetSourceCode(Arguments args) {
838 NoHandleAllocation ha;
839 ASSERT(args.length() == 1);
840
841 CONVERT_CHECKED(JSFunction, f, args[0]);
842 return f->shared()->GetSourceCode();
843}
844
845
846static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
847 NoHandleAllocation ha;
848 ASSERT(args.length() == 1);
849
850 CONVERT_CHECKED(JSFunction, fun, args[0]);
851 int pos = fun->shared()->start_position();
852 return Smi::FromInt(pos);
853}
854
855
856static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
857 NoHandleAllocation ha;
858 ASSERT(args.length() == 2);
859
860 CONVERT_CHECKED(JSFunction, fun, args[0]);
861 CONVERT_CHECKED(String, name, args[1]);
862 fun->SetInstanceClassName(name);
863 return Heap::undefined_value();
864}
865
866
867static Object* Runtime_FunctionSetLength(Arguments args) {
868 NoHandleAllocation ha;
869 ASSERT(args.length() == 2);
870
871 CONVERT_CHECKED(JSFunction, fun, args[0]);
872 CONVERT_CHECKED(Smi, length, args[1]);
873 fun->shared()->set_length(length->value());
874 return length;
875}
876
877
878static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000879 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 ASSERT(args.length() == 2);
881
882 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000883 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
884 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 return args[0]; // return TOS
886}
887
888
889static Object* Runtime_SetCode(Arguments args) {
890 HandleScope scope;
891 ASSERT(args.length() == 2);
892
893 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
894 Handle<JSFunction> target(raw_target);
895 Handle<Object> code = args.at<Object>(1);
896
897 Handle<Context> context(target->context());
898
899 if (!code->IsNull()) {
900 RUNTIME_ASSERT(code->IsJSFunction());
901 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
902 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
903 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
904 return Failure::Exception();
905 }
906 // Set the code, formal parameter count, and the length of the target
907 // function.
908 target->set_code(fun->code());
909 target->shared()->set_length(fun->shared()->length());
910 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000911 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000912 // Set the source code of the target function to undefined.
913 // SetCode is only used for built-in constructors like String,
914 // Array, and Object, and some web code
915 // doesn't like seeing source code for constructors.
916 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 context = Handle<Context>(fun->context());
918
919 // Make sure we get a fresh copy of the literal vector to avoid
920 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000921 int number_of_literals = fun->NumberOfLiterals();
922 Handle<FixedArray> literals =
923 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 // Insert the object, regexp and array functions in the literals
926 // array prefix. These are the functions that will be used when
927 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +0000928 literals->set(JSFunction::kLiteralGlobalContextIndex,
929 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000931 target->set_literals(*literals);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 }
933
934 target->set_context(*context);
935 return *target;
936}
937
938
939static Object* CharCodeAt(String* subject, Object* index) {
940 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000941 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // Flatten the string. If someone wants to get a char at an index
943 // in a cons string, it is likely that more indices will be
944 // accessed.
945 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000946 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 return Smi::FromInt(subject->Get(i));
948}
949
950
951static Object* Runtime_StringCharCodeAt(Arguments args) {
952 NoHandleAllocation ha;
953 ASSERT(args.length() == 2);
954
955 CONVERT_CHECKED(String, subject, args[0]);
956 Object* index = args[1];
957 return CharCodeAt(subject, index);
958}
959
960
961static Object* Runtime_CharFromCode(Arguments args) {
962 NoHandleAllocation ha;
963 ASSERT(args.length() == 1);
964 uint32_t code;
965 if (Array::IndexFromObject(args[0], &code)) {
966 if (code <= 0xffff) {
967 return Heap::LookupSingleCharacterStringFromCode(code);
968 }
969 }
970 return Heap::empty_string();
971}
972
973
ager@chromium.org7c537e22008-10-16 08:43:32 +0000974// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
975// limit, we can fix the size of tables.
976static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000977// Reduce alphabet to this size.
978static const int kBMAlphabetSize = 0x100;
979// For patterns below this length, the skip length of Boyer-Moore is too short
980// to compensate for the algorithmic overhead compared to simple brute force.
981static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982
ager@chromium.org7c537e22008-10-16 08:43:32 +0000983// Holds the two buffers used by Boyer-Moore string search's Good Suffix
984// shift. Only allows the last kBMMaxShift characters of the needle
985// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000986class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000987 public:
988 BMGoodSuffixBuffers() {}
989 inline void init(int needle_length) {
990 ASSERT(needle_length > 1);
991 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
992 int len = needle_length - start;
993 biased_suffixes_ = suffixes_ - start;
994 biased_good_suffix_shift_ = good_suffix_shift_ - start;
995 for (int i = 0; i <= len; i++) {
996 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000998 }
999 inline int& suffix(int index) {
1000 ASSERT(biased_suffixes_ + index >= suffixes_);
1001 return biased_suffixes_[index];
1002 }
1003 inline int& shift(int index) {
1004 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1005 return biased_good_suffix_shift_[index];
1006 }
1007 private:
1008 int suffixes_[kBMMaxShift + 1];
1009 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001010 int* biased_suffixes_;
1011 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001012 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1013};
1014
1015// buffers reused by BoyerMoore
1016static int bad_char_occurence[kBMAlphabetSize];
1017static BMGoodSuffixBuffers bmgs_buffers;
1018
1019// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001020template <typename pchar>
1021static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1022 int start) {
1023 // Run forwards to populate bad_char_table, so that *last* instance
1024 // of character equivalence class is the one registered.
1025 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001026 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1027 : kBMAlphabetSize;
1028 if (start == 0) { // All patterns less than kBMMaxShift in length.
1029 memset(bad_char_occurence, -1, table_size * sizeof(*bad_char_occurence));
1030 } else {
1031 for (int i = 0; i < table_size; i++) {
1032 bad_char_occurence[i] = start - 1;
1033 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001034 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001035 for (int i = start; i < pattern.length() - 1; i++) {
1036 pchar c = pattern[i];
1037 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
1038 bad_char_occurence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001039 }
1040}
1041
1042template <typename pchar>
1043static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001044 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001045 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001046 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001047 // Compute Good Suffix tables.
1048 bmgs_buffers.init(m);
1049
1050 bmgs_buffers.shift(m-1) = 1;
1051 bmgs_buffers.suffix(m) = m + 1;
1052 pchar last_char = pattern[m - 1];
1053 int suffix = m + 1;
1054 for (int i = m; i > start;) {
1055 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1056 if (bmgs_buffers.shift(suffix) == len) {
1057 bmgs_buffers.shift(suffix) = suffix - i;
1058 }
1059 suffix = bmgs_buffers.suffix(suffix);
1060 }
1061 i--;
1062 suffix--;
1063 bmgs_buffers.suffix(i) = suffix;
1064 if (suffix == m) {
1065 // No suffix to extend, so we check against last_char only.
1066 while (i > start && pattern[i - 1] != last_char) {
1067 if (bmgs_buffers.shift(m) == len) {
1068 bmgs_buffers.shift(m) = m - i;
1069 }
1070 i--;
1071 bmgs_buffers.suffix(i) = m;
1072 }
1073 if (i > start) {
1074 i--;
1075 suffix--;
1076 bmgs_buffers.suffix(i) = suffix;
1077 }
1078 }
1079 }
1080 if (suffix < m) {
1081 for (int i = start; i <= m; i++) {
1082 if (bmgs_buffers.shift(i) == len) {
1083 bmgs_buffers.shift(i) = suffix - start;
1084 }
1085 if (i == suffix) {
1086 suffix = bmgs_buffers.suffix(suffix);
1087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 }
1089 }
1090}
1091
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001092template <typename schar, typename pchar>
1093static inline int CharOccurence(int char_code) {
1094 if (sizeof(schar) == 1) {
1095 return bad_char_occurence[char_code];
1096 }
1097 if (sizeof(pchar) == 1) {
1098 if (char_code > String::kMaxAsciiCharCode) {
1099 return -1;
1100 }
1101 return bad_char_occurence[char_code];
1102 }
1103 return bad_char_occurence[char_code % kBMAlphabetSize];
1104}
1105
1106// Restricted simplified Boyer-Moore string matching. Restricts tables to a
ager@chromium.org7c537e22008-10-16 08:43:32 +00001107// suffix of long pattern strings and handles only equivalence classes
1108// of the full alphabet. This allows us to ensure that tables take only
1109// a fixed amount of space.
1110template <typename schar, typename pchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001111static int BoyerMooreSimplified(Vector<const schar> subject,
1112 Vector<const pchar> pattern,
1113 int start_index,
1114 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001115 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001116 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001117 // Only preprocess at most kBMMaxShift last characters of pattern.
1118 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119
ager@chromium.org7c537e22008-10-16 08:43:32 +00001120 BoyerMoorePopulateBadCharTable(pattern, start);
1121
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001122 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001123 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001124 pchar last_char = pattern[m - 1];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 // Perform search
1126 for (idx = start_index; idx <= n - m;) {
1127 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001128 int c;
1129 while (last_char != (c = subject[idx + j])) {
1130 int bc_occ = CharOccurence<schar, pchar>(c);
1131 int shift = j - bc_occ;
1132 idx += shift;
1133 badness += 1 - shift; // at most zero, so badness cannot increase.
1134 if (idx > n - m) {
1135 *complete = true;
1136 return -1;
1137 }
1138 }
1139 j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001140 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1141 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001142 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001143 return idx;
1144 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001145 int bc_occ = CharOccurence<schar, pchar>(c);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001146 int shift = bc_occ < j ? j - bc_occ : 1;
1147 idx += shift;
1148 // Badness increases by the number of characters we have
1149 // checked, and decreases by the number of characters we
1150 // can skip by shifting. It's a measure of how we are doing
1151 // compared to reading each character exactly once.
1152 badness += (m - j) - shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001153 if (badness > 0) {
1154 *complete = false;
1155 return idx;
1156 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001157 }
1158 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001159 *complete = true;
1160 return -1;
1161}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001162
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001163
1164template <typename schar, typename pchar>
1165static int BoyerMooreIndexOf(Vector<const schar> subject,
1166 Vector<const pchar> pattern,
1167 int idx) {
1168 int n = subject.length();
1169 int m = pattern.length();
1170 // Only preprocess at most kBMMaxShift last characters of pattern.
1171 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1172
1173 // Build the Good Suffix table and continue searching.
1174 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1175 pchar last_char = pattern[m - 1];
1176 // Continue search from i.
1177 do {
1178 int j = m - 1;
1179 schar c;
1180 while (last_char != (c = subject[idx + j])) {
1181 int shift = j - CharOccurence<schar, pchar>(c);
1182 idx += shift;
1183 if (idx > n - m) {
1184 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001185 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001186 }
1187 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1188 if (j < 0) {
1189 return idx;
1190 } else if (j < start) {
1191 // we have matched more than our tables allow us to be smart about.
1192 idx += 1;
1193 } else {
1194 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
1195 int bc_occ = CharOccurence<schar, pchar>(c);
1196 int shift = j - bc_occ; // Bad-char shift.
1197 shift = (gs_shift > shift) ? gs_shift : shift;
1198 idx += shift;
1199 }
1200 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001201
1202 return -1;
1203}
1204
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001205
1206template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001207static int SingleCharIndexOf(Vector<const schar> string,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001208 uc16 pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001209 int start_index) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001210 if (sizeof(schar) == 1 && pattern_char > String::kMaxAsciiCharCode) {
1211 return -1;
1212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001213 for (int i = start_index, n = string.length(); i < n; i++) {
1214 if (pattern_char == string[i]) {
1215 return i;
1216 }
1217 }
1218 return -1;
1219}
1220
1221// Trivial string search for shorter strings.
1222// On return, if "complete" is set to true, the return value is the
1223// final result of searching for the patter in the subject.
1224// If "complete" is set to false, the return value is the index where
1225// further checking should start, i.e., it's guaranteed that the pattern
1226// does not occur at a position prior to the returned index.
1227template <typename pchar, typename schar>
1228static int SimpleIndexOf(Vector<const schar> subject,
1229 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001230 int idx,
1231 bool* complete) {
1232 // Badness is a count of how much work we have done. When we have
1233 // done enough work we decide it's probably worth switching to a better
1234 // algorithm.
1235 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001236 // We know our pattern is at least 2 characters, we cache the first so
1237 // the common case of the first character not matching is faster.
1238 pchar pattern_first_char = pattern[0];
1239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001240 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1241 badness++;
1242 if (badness > 0) {
1243 *complete = false;
1244 return (i);
1245 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001246 if (subject[i] != pattern_first_char) continue;
1247 int j = 1;
1248 do {
1249 if (pattern[j] != subject[i+j]) {
1250 break;
1251 }
1252 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001253 } while (j < pattern.length());
1254 if (j == pattern.length()) {
1255 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001256 return i;
1257 }
1258 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001259 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001260 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001261 return -1;
1262}
1263
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001264// Simple indexOf that never bails out. For short patterns only.
1265template <typename pchar, typename schar>
1266static int SimpleIndexOf(Vector<const schar> subject,
1267 Vector<const pchar> pattern,
1268 int idx) {
1269 pchar pattern_first_char = pattern[0];
1270 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1271 if (subject[i] != pattern_first_char) continue;
1272 int j = 1;
1273 do {
1274 if (pattern[j] != subject[i+j]) {
1275 break;
1276 }
1277 j++;
1278 } while (j < pattern.length());
1279 if (j == pattern.length()) {
1280 return i;
1281 }
1282 }
1283 return -1;
1284}
1285
1286
1287// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001288template <typename schar, typename pchar>
1289static int StringMatchStrategy(Vector<const schar> sub,
1290 Vector<const pchar> pat,
1291 int start_index) {
1292 ASSERT(pat.length() > 1);
1293
1294 // We have an ASCII haystack and a non-ASCII needle. Check if there
1295 // really is a non-ASCII character in the needle and bail out if there
1296 // is.
1297 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1298 for (int i = 0; i < pat.length(); i++) {
1299 uc16 c = pat[i];
1300 if (c > String::kMaxAsciiCharCode) {
1301 return -1;
1302 }
1303 }
1304 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001305 if (pat.length() < kBMMinPatternLength) {
1306 // We don't believe fancy searching can ever be more efficient.
1307 // The max shift of Boyer-Moore on a pattern of this length does
1308 // not compensate for the overhead.
1309 return SimpleIndexOf(sub, pat, start_index);
1310 }
1311 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001312 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001313 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1314 if (complete) return idx;
1315 idx = BoyerMooreSimplified(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001316 if (complete) return idx;
1317 return BoyerMooreIndexOf(sub, pat, idx);
1318}
1319
1320// Perform string match of pattern on subject, starting at start index.
1321// Caller must ensure that 0 <= start_index <= sub->length(),
1322// and should check that pat->length() + start_index <= sub->length()
1323int Runtime::StringMatch(Handle<String> sub,
1324 Handle<String> pat,
1325 int start_index) {
1326 ASSERT(0 <= start_index);
1327 ASSERT(start_index <= sub->length());
1328
ager@chromium.org236ad962008-09-25 09:45:57 +00001329 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001330 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
ager@chromium.org7c537e22008-10-16 08:43:32 +00001332 int subject_length = sub->length();
1333 if (start_index + pattern_length > subject_length) return -1;
1334
1335 FlattenString(sub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 // character patterns linear search is necessary, so any smart
1338 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001340 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1341 if (sub->is_ascii_representation()) {
1342 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001344 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 }
1346
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00001348
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1350 // dispatch on type of strings
1351 if (pat->is_ascii_representation()) {
1352 Vector<const char> pat_vector = pat->ToAsciiVector();
1353 if (sub->is_ascii_representation()) {
1354 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001355 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001356 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001357 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001358 Vector<const uc16> pat_vector = pat->ToUC16Vector();
1359 if (sub->is_ascii_representation()) {
1360 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001362 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001363}
1364
1365
1366static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001368 ASSERT(args.length() == 3);
1369
ager@chromium.org7c537e22008-10-16 08:43:32 +00001370 CONVERT_ARG_CHECKED(String, sub, 0);
1371 CONVERT_ARG_CHECKED(String, pat, 1);
1372
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001373 Object* index = args[2];
1374 uint32_t start_index;
1375 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 int position = Runtime::StringMatch(sub, pat, start_index);
1378 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379}
1380
1381
1382static Object* Runtime_StringLastIndexOf(Arguments args) {
1383 NoHandleAllocation ha;
1384 ASSERT(args.length() == 3);
1385
1386 CONVERT_CHECKED(String, sub, args[0]);
1387 CONVERT_CHECKED(String, pat, args[1]);
1388 Object* index = args[2];
1389
1390 sub->TryFlatten();
1391 pat->TryFlatten();
1392
1393 uint32_t start_index;
1394 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1395
1396 uint32_t pattern_length = pat->length();
1397 uint32_t sub_length = sub->length();
1398
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001399 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402
1403 for (int i = start_index; i >= 0; i--) {
1404 bool found = true;
1405 for (uint32_t j = 0; j < pattern_length; j++) {
1406 if (sub->Get(i + j) != pat->Get(j)) {
1407 found = false;
1408 break;
1409 }
1410 }
1411 if (found) return Smi::FromInt(i);
1412 }
1413
1414 return Smi::FromInt(-1);
1415}
1416
1417
1418static Object* Runtime_StringLocaleCompare(Arguments args) {
1419 NoHandleAllocation ha;
1420 ASSERT(args.length() == 2);
1421
1422 CONVERT_CHECKED(String, str1, args[0]);
1423 CONVERT_CHECKED(String, str2, args[1]);
1424
1425 if (str1 == str2) return Smi::FromInt(0); // Equal.
1426 int str1_length = str1->length();
1427 int str2_length = str2->length();
1428
1429 // Decide trivial cases without flattening.
1430 if (str1_length == 0) {
1431 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1432 return Smi::FromInt(-str2_length);
1433 } else {
1434 if (str2_length == 0) return Smi::FromInt(str1_length);
1435 }
1436
1437 int end = str1_length < str2_length ? str1_length : str2_length;
1438
1439 // No need to flatten if we are going to find the answer on the first
1440 // character. At this point we know there is at least one character
1441 // in each string, due to the trivial case handling above.
1442 int d = str1->Get(0) - str2->Get(0);
1443 if (d != 0) return Smi::FromInt(d);
1444
1445 str1->TryFlatten();
1446 str2->TryFlatten();
1447
1448 static StringInputBuffer buf1;
1449 static StringInputBuffer buf2;
1450
1451 buf1.Reset(str1);
1452 buf2.Reset(str2);
1453
1454 for (int i = 0; i < end; i++) {
1455 uint16_t char1 = buf1.GetNext();
1456 uint16_t char2 = buf2.GetNext();
1457 if (char1 != char2) return Smi::FromInt(char1 - char2);
1458 }
1459
1460 return Smi::FromInt(str1_length - str2_length);
1461}
1462
1463
1464static Object* Runtime_StringSlice(Arguments args) {
1465 NoHandleAllocation ha;
1466 ASSERT(args.length() == 3);
1467
1468 CONVERT_CHECKED(String, value, args[0]);
1469 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1470 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1471
1472 int start = FastD2I(from_number);
1473 int end = FastD2I(to_number);
1474
1475 RUNTIME_ASSERT(end >= start);
1476 RUNTIME_ASSERT(start >= 0);
1477 RUNTIME_ASSERT(end <= value->length());
1478 return value->Slice(start, end);
1479}
1480
1481
1482static Object* Runtime_NumberToRadixString(Arguments args) {
1483 NoHandleAllocation ha;
1484 ASSERT(args.length() == 2);
1485
1486 CONVERT_DOUBLE_CHECKED(value, args[0]);
1487 if (isnan(value)) {
1488 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1489 }
1490 if (isinf(value)) {
1491 if (value < 0) {
1492 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1493 }
1494 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1495 }
1496 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1497 int radix = FastD2I(radix_number);
1498 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1499 char* str = DoubleToRadixCString(value, radix);
1500 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1501 DeleteArray(str);
1502 return result;
1503}
1504
1505
1506static Object* Runtime_NumberToFixed(Arguments args) {
1507 NoHandleAllocation ha;
1508 ASSERT(args.length() == 2);
1509
1510 CONVERT_DOUBLE_CHECKED(value, args[0]);
1511 if (isnan(value)) {
1512 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1513 }
1514 if (isinf(value)) {
1515 if (value < 0) {
1516 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1517 }
1518 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1519 }
1520 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1521 int f = FastD2I(f_number);
1522 RUNTIME_ASSERT(f >= 0);
1523 char* str = DoubleToFixedCString(value, f);
1524 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1525 DeleteArray(str);
1526 return res;
1527}
1528
1529
1530static Object* Runtime_NumberToExponential(Arguments args) {
1531 NoHandleAllocation ha;
1532 ASSERT(args.length() == 2);
1533
1534 CONVERT_DOUBLE_CHECKED(value, args[0]);
1535 if (isnan(value)) {
1536 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1537 }
1538 if (isinf(value)) {
1539 if (value < 0) {
1540 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1541 }
1542 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1543 }
1544 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1545 int f = FastD2I(f_number);
1546 RUNTIME_ASSERT(f >= -1 && f <= 20);
1547 char* str = DoubleToExponentialCString(value, f);
1548 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1549 DeleteArray(str);
1550 return res;
1551}
1552
1553
1554static Object* Runtime_NumberToPrecision(Arguments args) {
1555 NoHandleAllocation ha;
1556 ASSERT(args.length() == 2);
1557
1558 CONVERT_DOUBLE_CHECKED(value, args[0]);
1559 if (isnan(value)) {
1560 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1561 }
1562 if (isinf(value)) {
1563 if (value < 0) {
1564 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1565 }
1566 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1567 }
1568 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1569 int f = FastD2I(f_number);
1570 RUNTIME_ASSERT(f >= 1 && f <= 21);
1571 char* str = DoubleToPrecisionCString(value, f);
1572 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1573 DeleteArray(str);
1574 return res;
1575}
1576
1577
1578// Returns a single character string where first character equals
1579// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001580static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 if (index < static_cast<uint32_t>(string->length())) {
1582 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001583 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001585 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586}
1587
1588
1589Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1590 // Handle [] indexing on Strings
1591 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001592 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1593 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595
1596 // Handle [] indexing on String objects
1597 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001598 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1599 Handle<Object> result =
1600 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1601 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603
1604 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001605 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 return prototype->GetElement(index);
1607 }
1608
1609 return object->GetElement(index);
1610}
1611
1612
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001613Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1614 HandleScope scope;
1615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001617 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 Handle<Object> error =
1619 Factory::NewTypeError("non_object_property_load",
1620 HandleVector(args, 2));
1621 return Top::Throw(*error);
1622 }
1623
1624 // Check if the given key is an array index.
1625 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001626 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 return GetElementOrCharAt(object, index);
1628 }
1629
1630 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001631 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001633 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 bool has_pending_exception = false;
1636 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001637 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001639 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 }
1641
1642 // Check if the name is trivially convertable to an index and get
1643 // the element if so.
1644 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 return GetElementOrCharAt(object, index);
1646 } else {
1647 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001648 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 }
1650}
1651
1652
1653static Object* Runtime_GetProperty(Arguments args) {
1654 NoHandleAllocation ha;
1655 ASSERT(args.length() == 2);
1656
1657 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001658 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659
1660 return Runtime::GetObjectProperty(object, key);
1661}
1662
1663
ager@chromium.org7c537e22008-10-16 08:43:32 +00001664
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001665// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001666static Object* Runtime_KeyedGetProperty(Arguments args) {
1667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 2);
1669
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001670 // Fast cases for getting named properties of the receiver JSObject
1671 // itself. The global proxy objects has to be excluded since
1672 // LocalLookup on the global proxy object can return a valid result
1673 // eventhough the global proxy object never has properties. This is
1674 // the case because the global proxy object forwards everything to
1675 // its hidden prototype including local lookups.
1676 if (args[0]->IsJSObject() &&
1677 !args[0]->IsJSGlobalProxy() &&
1678 args[1]->IsString()) {
1679 JSObject* receiver = JSObject::cast(args[0]);
1680 String* key = String::cast(args[1]);
1681 if (receiver->HasFastProperties()) {
1682 // Attempt to use lookup cache.
1683 Object* obj = Heap::GetKeyedLookupCache();
1684 if (obj->IsFailure()) return obj;
1685 LookupCache* cache = LookupCache::cast(obj);
1686 Map* receiver_map = receiver->map();
1687 int offset = cache->Lookup(receiver_map, key);
1688 if (offset != LookupCache::kNotFound) {
1689 Object* value = receiver->FastPropertyAt(offset);
1690 return value->IsTheHole() ? Heap::undefined_value() : value;
1691 }
1692 // Lookup cache miss. Perform lookup and update the cache if
1693 // appropriate.
1694 LookupResult result;
1695 receiver->LocalLookup(key, &result);
1696 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1697 int offset = result.GetFieldIndex();
1698 Object* obj = cache->Put(receiver_map, key, offset);
1699 if (obj->IsFailure()) return obj;
1700 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1701 Object* value = receiver->FastPropertyAt(offset);
1702 return value->IsTheHole() ? Heap::undefined_value() : value;
1703 }
1704 } else {
1705 // Attempt dictionary lookup.
1706 Dictionary* dictionary = receiver->property_dictionary();
1707 int entry = dictionary->FindStringEntry(key);
1708 if ((entry != DescriptorArray::kNotFound) &&
1709 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1710 return dictionary->ValueAt(entry);
1711 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001712 }
1713 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001714
1715 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001716 return Runtime::GetObjectProperty(args.at<Object>(0),
1717 args.at<Object>(1));
1718}
1719
1720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001721Object* Runtime::SetObjectProperty(Handle<Object> object,
1722 Handle<Object> key,
1723 Handle<Object> value,
1724 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001725 HandleScope scope;
1726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001728 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 Handle<Object> error =
1730 Factory::NewTypeError("non_object_property_store",
1731 HandleVector(args, 2));
1732 return Top::Throw(*error);
1733 }
1734
1735 // If the object isn't a JavaScript object, we ignore the store.
1736 if (!object->IsJSObject()) return *value;
1737
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 // Check if the given key is an array index.
1741 uint32_t index;
1742 if (Array::IndexFromObject(*key, &index)) {
1743 ASSERT(attr == NONE);
1744
1745 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1746 // of a string using [] notation. We need to support this too in
1747 // JavaScript.
1748 // In the case of a String object we just need to redirect the assignment to
1749 // the underlying string if the index is in range. Since the underlying
1750 // string does nothing with the assignment then we can ignore such
1751 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001752 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001753 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001756 Handle<Object> result = SetElement(js_object, index, value);
1757 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 return *value;
1759 }
1760
1761 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001762 Handle<Object> result;
1763 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001765 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001767 Handle<String> key_string = Handle<String>::cast(key);
1768 key_string->TryFlatten();
1769 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001771 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 return *value;
1773 }
1774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001776 bool has_pending_exception = false;
1777 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1778 if (has_pending_exception) return Failure::Exception();
1779 Handle<String> name = Handle<String>::cast(converted);
1780
1781 if (name->AsArrayIndex(&index)) {
1782 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001783 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001785 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786 }
1787}
1788
1789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790static Object* Runtime_SetProperty(Arguments args) {
1791 NoHandleAllocation ha;
1792 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1793
1794 Handle<Object> object = args.at<Object>(0);
1795 Handle<Object> key = args.at<Object>(1);
1796 Handle<Object> value = args.at<Object>(2);
1797
1798 // Compute attributes.
1799 PropertyAttributes attributes = NONE;
1800 if (args.length() == 4) {
1801 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001804 RUNTIME_ASSERT(
1805 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1806 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 }
1808 return Runtime::SetObjectProperty(object, key, value, attributes);
1809}
1810
1811
1812// Set a local property, even if it is READ_ONLY. If the property does not
1813// exist, it will be added with attributes NONE.
1814static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1815 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 CONVERT_CHECKED(JSObject, object, args[0]);
1818 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001819 // Compute attributes.
1820 PropertyAttributes attributes = NONE;
1821 if (args.length() == 4) {
1822 CONVERT_CHECKED(Smi, value_obj, args[3]);
1823 int unchecked_value = value_obj->value();
1824 // Only attribute bits should be set.
1825 RUNTIME_ASSERT(
1826 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1827 attributes = static_cast<PropertyAttributes>(unchecked_value);
1828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001830 return object->
1831 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832}
1833
1834
1835static Object* Runtime_DeleteProperty(Arguments args) {
1836 NoHandleAllocation ha;
1837 ASSERT(args.length() == 2);
1838
1839 CONVERT_CHECKED(JSObject, object, args[0]);
1840 CONVERT_CHECKED(String, key, args[1]);
1841 return object->DeleteProperty(key);
1842}
1843
1844
1845static Object* Runtime_HasLocalProperty(Arguments args) {
1846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 2);
1848 CONVERT_CHECKED(String, key, args[1]);
1849
1850 // Only JS objects can have properties.
1851 if (args[0]->IsJSObject()) {
1852 JSObject* object = JSObject::cast(args[0]);
1853 if (object->HasLocalProperty(key)) return Heap::true_value();
1854 } else if (args[0]->IsString()) {
1855 // Well, there is one exception: Handle [] on strings.
1856 uint32_t index;
1857 if (key->AsArrayIndex(&index)) {
1858 String* string = String::cast(args[0]);
1859 if (index < static_cast<uint32_t>(string->length()))
1860 return Heap::true_value();
1861 }
1862 }
1863 return Heap::false_value();
1864}
1865
1866
1867static Object* Runtime_HasProperty(Arguments args) {
1868 NoHandleAllocation na;
1869 ASSERT(args.length() == 2);
1870
1871 // Only JS objects can have properties.
1872 if (args[0]->IsJSObject()) {
1873 JSObject* object = JSObject::cast(args[0]);
1874 CONVERT_CHECKED(String, key, args[1]);
1875 if (object->HasProperty(key)) return Heap::true_value();
1876 }
1877 return Heap::false_value();
1878}
1879
1880
1881static Object* Runtime_HasElement(Arguments args) {
1882 NoHandleAllocation na;
1883 ASSERT(args.length() == 2);
1884
1885 // Only JS objects can have elements.
1886 if (args[0]->IsJSObject()) {
1887 JSObject* object = JSObject::cast(args[0]);
1888 CONVERT_CHECKED(Smi, index_obj, args[1]);
1889 uint32_t index = index_obj->value();
1890 if (object->HasElement(index)) return Heap::true_value();
1891 }
1892 return Heap::false_value();
1893}
1894
1895
1896static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1897 NoHandleAllocation ha;
1898 ASSERT(args.length() == 2);
1899
1900 CONVERT_CHECKED(JSObject, object, args[0]);
1901 CONVERT_CHECKED(String, key, args[1]);
1902
1903 uint32_t index;
1904 if (key->AsArrayIndex(&index)) {
1905 return Heap::ToBoolean(object->HasElement(index));
1906 }
1907
1908 LookupResult result;
1909 object->LocalLookup(key, &result);
1910 if (!result.IsProperty()) return Heap::false_value();
1911 return Heap::ToBoolean(!result.IsDontEnum());
1912}
1913
1914
1915static Object* Runtime_GetPropertyNames(Arguments args) {
1916 HandleScope scope;
1917 ASSERT(args.length() == 1);
1918
1919 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1920 Handle<JSObject> object(raw_object);
1921 return *GetKeysFor(object);
1922}
1923
1924
1925// Returns either a FixedArray as Runtime_GetPropertyNames,
1926// or, if the given object has an enum cache that contains
1927// all enumerable properties of the object and its prototypes
1928// have none, the map of the object. This is used to speed up
1929// the check for deletions during a for-in.
1930static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1931 ASSERT(args.length() == 1);
1932
1933 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1934
1935 if (raw_object->IsSimpleEnum()) return raw_object->map();
1936
1937 HandleScope scope;
1938 Handle<JSObject> object(raw_object);
1939 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1940
1941 // Test again, since cache may have been built by preceding call.
1942 if (object->IsSimpleEnum()) return object->map();
1943
1944 return *content;
1945}
1946
1947
1948static Object* Runtime_GetArgumentsProperty(Arguments args) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
1952 // Compute the frame holding the arguments.
1953 JavaScriptFrameIterator it;
1954 it.AdvanceToArgumentsFrame();
1955 JavaScriptFrame* frame = it.frame();
1956
1957 // Get the actual number of provided arguments.
1958 const uint32_t n = frame->GetProvidedParametersCount();
1959
1960 // Try to convert the key to an index. If successful and within
1961 // index return the the argument from the frame.
1962 uint32_t index;
1963 if (Array::IndexFromObject(args[0], &index) && index < n) {
1964 return frame->GetParameter(index);
1965 }
1966
1967 // Convert the key to a string.
1968 HandleScope scope;
1969 bool exception = false;
1970 Handle<Object> converted =
1971 Execution::ToString(args.at<Object>(0), &exception);
1972 if (exception) return Failure::Exception();
1973 Handle<String> key = Handle<String>::cast(converted);
1974
1975 // Try to convert the string key into an array index.
1976 if (key->AsArrayIndex(&index)) {
1977 if (index < n) {
1978 return frame->GetParameter(index);
1979 } else {
1980 return Top::initial_object_prototype()->GetElement(index);
1981 }
1982 }
1983
1984 // Handle special arguments properties.
1985 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1986 if (key->Equals(Heap::callee_symbol())) return frame->function();
1987
1988 // Lookup in the initial Object.prototype object.
1989 return Top::initial_object_prototype()->GetProperty(*key);
1990}
1991
1992
1993static Object* Runtime_ToBool(Arguments args) {
1994 NoHandleAllocation ha;
1995 ASSERT(args.length() == 1);
1996
1997 return args[0]->ToBoolean();
1998}
1999
2000
2001// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2002// Possible optimizations: put the type string into the oddballs.
2003static Object* Runtime_Typeof(Arguments args) {
2004 NoHandleAllocation ha;
2005
2006 Object* obj = args[0];
2007 if (obj->IsNumber()) return Heap::number_symbol();
2008 HeapObject* heap_obj = HeapObject::cast(obj);
2009
2010 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002011 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012
2013 InstanceType instance_type = heap_obj->map()->instance_type();
2014 if (instance_type < FIRST_NONSTRING_TYPE) {
2015 return Heap::string_symbol();
2016 }
2017
2018 switch (instance_type) {
2019 case ODDBALL_TYPE:
2020 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2021 return Heap::boolean_symbol();
2022 }
2023 if (heap_obj->IsNull()) {
2024 return Heap::object_symbol();
2025 }
2026 ASSERT(heap_obj->IsUndefined());
2027 return Heap::undefined_symbol();
2028 case JS_FUNCTION_TYPE:
2029 return Heap::function_symbol();
2030 default:
2031 // For any kind of object not handled above, the spec rule for
2032 // host objects gives that it is okay to return "object"
2033 return Heap::object_symbol();
2034 }
2035}
2036
2037
2038static Object* Runtime_StringToNumber(Arguments args) {
2039 NoHandleAllocation ha;
2040 ASSERT(args.length() == 1);
2041 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002042 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2044}
2045
2046
2047static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2048 NoHandleAllocation ha;
2049 ASSERT(args.length() == 1);
2050
2051 CONVERT_CHECKED(JSArray, codes, args[0]);
2052 int length = Smi::cast(codes->length())->value();
2053
2054 // Check if the string can be ASCII.
2055 int i;
2056 for (i = 0; i < length; i++) {
2057 Object* element = codes->GetElement(i);
2058 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2059 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2060 break;
2061 }
2062
2063 Object* object = NULL;
2064 if (i == length) { // The string is ASCII.
2065 object = Heap::AllocateRawAsciiString(length);
2066 } else { // The string is not ASCII.
2067 object = Heap::AllocateRawTwoByteString(length);
2068 }
2069
2070 if (object->IsFailure()) return object;
2071 String* result = String::cast(object);
2072 for (int i = 0; i < length; i++) {
2073 Object* element = codes->GetElement(i);
2074 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2075 result->Set(i, chr & 0xffff);
2076 }
2077 return result;
2078}
2079
2080
2081// kNotEscaped is generated by the following:
2082//
2083// #!/bin/perl
2084// for (my $i = 0; $i < 256; $i++) {
2085// print "\n" if $i % 16 == 0;
2086// my $c = chr($i);
2087// my $escaped = 1;
2088// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2089// print $escaped ? "0, " : "1, ";
2090// }
2091
2092
2093static bool IsNotEscaped(uint16_t character) {
2094 // Only for 8 bit characters, the rest are always escaped (in a different way)
2095 ASSERT(character < 256);
2096 static const char kNotEscaped[256] = {
2097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
2100 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2101 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2103 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2113 };
2114 return kNotEscaped[character] != 0;
2115}
2116
2117
2118static Object* Runtime_URIEscape(Arguments args) {
2119 const char hex_chars[] = "0123456789ABCDEF";
2120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122 CONVERT_CHECKED(String, source, args[0]);
2123
2124 source->TryFlatten();
2125
2126 int escaped_length = 0;
2127 int length = source->length();
2128 {
2129 Access<StringInputBuffer> buffer(&string_input_buffer);
2130 buffer->Reset(source);
2131 while (buffer->has_more()) {
2132 uint16_t character = buffer->GetNext();
2133 if (character >= 256) {
2134 escaped_length += 6;
2135 } else if (IsNotEscaped(character)) {
2136 escaped_length++;
2137 } else {
2138 escaped_length += 3;
2139 }
2140 // We don't allow strings that are longer than Smi range.
2141 if (!Smi::IsValid(escaped_length)) {
2142 Top::context()->mark_out_of_memory();
2143 return Failure::OutOfMemoryException();
2144 }
2145 }
2146 }
2147 // No length change implies no change. Return original string if no change.
2148 if (escaped_length == length) {
2149 return source;
2150 }
2151 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2152 if (o->IsFailure()) return o;
2153 String* destination = String::cast(o);
2154 int dest_position = 0;
2155
2156 Access<StringInputBuffer> buffer(&string_input_buffer);
2157 buffer->Rewind();
2158 while (buffer->has_more()) {
2159 uint16_t character = buffer->GetNext();
2160 if (character >= 256) {
2161 destination->Set(dest_position, '%');
2162 destination->Set(dest_position+1, 'u');
2163 destination->Set(dest_position+2, hex_chars[character >> 12]);
2164 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
2165 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
2166 destination->Set(dest_position+5, hex_chars[character & 0xf]);
2167 dest_position += 6;
2168 } else if (IsNotEscaped(character)) {
2169 destination->Set(dest_position, character);
2170 dest_position++;
2171 } else {
2172 destination->Set(dest_position, '%');
2173 destination->Set(dest_position+1, hex_chars[character >> 4]);
2174 destination->Set(dest_position+2, hex_chars[character & 0xf]);
2175 dest_position += 3;
2176 }
2177 }
2178 return destination;
2179}
2180
2181
2182static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2183 static const signed char kHexValue['g'] = {
2184 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2185 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2186 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2187 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2188 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2189 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2190 -1, 10, 11, 12, 13, 14, 15 };
2191
2192 if (character1 > 'f') return -1;
2193 int hi = kHexValue[character1];
2194 if (hi == -1) return -1;
2195 if (character2 > 'f') return -1;
2196 int lo = kHexValue[character2];
2197 if (lo == -1) return -1;
2198 return (hi << 4) + lo;
2199}
2200
2201
2202static inline int Unescape(String* source, int i, int length, int* step) {
2203 uint16_t character = source->Get(i);
2204 int32_t hi, lo;
2205 if (character == '%' &&
2206 i <= length - 6 &&
2207 source->Get(i + 1) == 'u' &&
2208 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
2209 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
2210 *step = 6;
2211 return (hi << 8) + lo;
2212 } else if (character == '%' &&
2213 i <= length - 3 &&
2214 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
2215 *step = 3;
2216 return lo;
2217 } else {
2218 *step = 1;
2219 return character;
2220 }
2221}
2222
2223
2224static Object* Runtime_URIUnescape(Arguments args) {
2225 NoHandleAllocation ha;
2226 ASSERT(args.length() == 1);
2227 CONVERT_CHECKED(String, source, args[0]);
2228
2229 source->TryFlatten();
2230
2231 bool ascii = true;
2232 int length = source->length();
2233
2234 int unescaped_length = 0;
2235 for (int i = 0; i < length; unescaped_length++) {
2236 int step;
2237 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
2238 ascii = false;
2239 i += step;
2240 }
2241
2242 // No length change implies no change. Return original string if no change.
2243 if (unescaped_length == length)
2244 return source;
2245
2246 Object* o = ascii ?
2247 Heap::AllocateRawAsciiString(unescaped_length) :
2248 Heap::AllocateRawTwoByteString(unescaped_length);
2249 if (o->IsFailure()) return o;
2250 String* destination = String::cast(o);
2251
2252 int dest_position = 0;
2253 for (int i = 0; i < length; dest_position++) {
2254 int step;
2255 destination->Set(dest_position, Unescape(source, i, length, &step));
2256 i += step;
2257 }
2258 return destination;
2259}
2260
2261
2262static Object* Runtime_StringParseInt(Arguments args) {
2263 NoHandleAllocation ha;
2264
2265 CONVERT_CHECKED(String, s, args[0]);
2266 CONVERT_DOUBLE_CHECKED(n, args[1]);
2267 int radix = FastD2I(n);
2268
2269 s->TryFlatten();
2270
2271 int len = s->length();
2272 int i;
2273
2274 // Skip leading white space.
2275 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
2276 if (i == len) return Heap::nan_value();
2277
2278 // Compute the sign (default to +).
2279 int sign = 1;
2280 if (s->Get(i) == '-') {
2281 sign = -1;
2282 i++;
2283 } else if (s->Get(i) == '+') {
2284 i++;
2285 }
2286
2287 // Compute the radix if 0.
2288 if (radix == 0) {
2289 radix = 10;
2290 if (i < len && s->Get(i) == '0') {
2291 radix = 8;
2292 if (i + 1 < len) {
2293 int c = s->Get(i + 1);
2294 if (c == 'x' || c == 'X') {
2295 radix = 16;
2296 i += 2;
2297 }
2298 }
2299 }
2300 } else if (radix == 16) {
2301 // Allow 0x or 0X prefix if radix is 16.
2302 if (i + 1 < len && s->Get(i) == '0') {
2303 int c = s->Get(i + 1);
2304 if (c == 'x' || c == 'X') i += 2;
2305 }
2306 }
2307
2308 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2309 double value;
2310 int end_index = StringToInt(s, i, radix, &value);
2311 if (end_index != i) {
2312 return Heap::NumberFromDouble(sign * value);
2313 }
2314 return Heap::nan_value();
2315}
2316
2317
2318static Object* Runtime_StringParseFloat(Arguments args) {
2319 NoHandleAllocation ha;
2320 CONVERT_CHECKED(String, str, args[0]);
2321
2322 // ECMA-262 section 15.1.2.3, empty string is NaN
2323 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2324
2325 // Create a number object from the value.
2326 return Heap::NumberFromDouble(value);
2327}
2328
2329
2330static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2331static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2332
2333
2334template <class Converter>
2335static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002336 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002337 NoHandleAllocation ha;
2338
2339 CONVERT_CHECKED(String, s, args[0]);
2340 int raw_string_length = s->length();
2341 // Assume that the string is not empty; we need this assumption later
2342 if (raw_string_length == 0) return s;
2343 int length = raw_string_length;
2344
2345 s->TryFlatten();
2346
2347 // We try this twice, once with the assumption that the result is
2348 // no longer than the input and, if that assumption breaks, again
2349 // with the exact length. This is implemented using a goto back
2350 // to this label if we discover that the assumption doesn't hold.
2351 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002352 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002353 try_convert:
2354
2355 // Allocate the resulting string.
2356 //
2357 // NOTE: This assumes that the upper/lower case of an ascii
2358 // character is also ascii. This is currently the case, but it
2359 // might break in the future if we implement more context and locale
2360 // dependent upper/lower conversions.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002361 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002362 ? Heap::AllocateRawAsciiString(length)
2363 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002364 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002365 String* result = String::cast(o);
2366 bool has_changed_character = false;
2367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002368 // Convert all characters to upper case, assuming that they will fit
2369 // in the buffer
2370 Access<StringInputBuffer> buffer(&string_input_buffer);
2371 buffer->Reset(s);
2372 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
2373 int i = 0;
2374 // We can assume that the string is not empty
2375 uc32 current = buffer->GetNext();
2376 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002377 bool has_next = buffer->has_more();
2378 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002379 int char_length = mapping->get(current, next, chars);
2380 if (char_length == 0) {
2381 // The case conversion of this character is the character itself.
2382 result->Set(i, current);
2383 i++;
2384 } else if (char_length == 1) {
2385 // Common case: converting the letter resulted in one character.
2386 ASSERT(static_cast<uc32>(chars[0]) != current);
2387 result->Set(i, chars[0]);
2388 has_changed_character = true;
2389 i++;
2390 } else if (length == raw_string_length) {
2391 // We've assumed that the result would be as long as the
2392 // input but here is a character that converts to several
2393 // characters. No matter, we calculate the exact length
2394 // of the result and try the whole thing again.
2395 //
2396 // Note that this leaves room for optimization. We could just
2397 // memcpy what we already have to the result string. Also,
2398 // the result string is the last object allocated we could
2399 // "realloc" it and probably, in the vast majority of cases,
2400 // extend the existing string to be able to hold the full
2401 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002402 int next_length = 0;
2403 if (has_next) {
2404 next_length = mapping->get(next, 0, chars);
2405 if (next_length == 0) next_length = 1;
2406 }
2407 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002408 while (buffer->has_more()) {
2409 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002410 // NOTE: we use 0 as the next character here because, while
2411 // the next character may affect what a character converts to,
2412 // it does not in any case affect the length of what it convert
2413 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002414 int char_length = mapping->get(current, 0, chars);
2415 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002416 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417 }
2418 length = current_length;
2419 goto try_convert;
2420 } else {
2421 for (int j = 0; j < char_length; j++) {
2422 result->Set(i, chars[j]);
2423 i++;
2424 }
2425 has_changed_character = true;
2426 }
2427 current = next;
2428 }
2429 if (has_changed_character) {
2430 return result;
2431 } else {
2432 // If we didn't actually change anything in doing the conversion
2433 // we simple return the result and let the converted string
2434 // become garbage; there is no reason to keep two identical strings
2435 // alive.
2436 return s;
2437 }
2438}
2439
2440
2441static Object* Runtime_StringToLowerCase(Arguments args) {
2442 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2443}
2444
2445
2446static Object* Runtime_StringToUpperCase(Arguments args) {
2447 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2448}
2449
2450
2451static Object* Runtime_ConsStringFst(Arguments args) {
2452 NoHandleAllocation ha;
2453
2454 CONVERT_CHECKED(ConsString, str, args[0]);
2455 return str->first();
2456}
2457
2458
2459static Object* Runtime_ConsStringSnd(Arguments args) {
2460 NoHandleAllocation ha;
2461
2462 CONVERT_CHECKED(ConsString, str, args[0]);
2463 return str->second();
2464}
2465
2466
2467static Object* Runtime_NumberToString(Arguments args) {
2468 NoHandleAllocation ha;
2469 ASSERT(args.length() == 1);
2470
2471 Object* number = args[0];
2472 RUNTIME_ASSERT(number->IsNumber());
2473
2474 Object* cached = Heap::GetNumberStringCache(number);
2475 if (cached != Heap::undefined_value()) {
2476 return cached;
2477 }
2478
2479 char arr[100];
2480 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2481 const char* str;
2482 if (number->IsSmi()) {
2483 int num = Smi::cast(number)->value();
2484 str = IntToCString(num, buffer);
2485 } else {
2486 double num = HeapNumber::cast(number)->value();
2487 str = DoubleToCString(num, buffer);
2488 }
2489 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2490
2491 if (!result->IsFailure()) {
2492 Heap::SetNumberStringCache(number, String::cast(result));
2493 }
2494 return result;
2495}
2496
2497
2498static Object* Runtime_NumberToInteger(Arguments args) {
2499 NoHandleAllocation ha;
2500 ASSERT(args.length() == 1);
2501
2502 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002503 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504 CONVERT_DOUBLE_CHECKED(number, obj);
2505 return Heap::NumberFromDouble(DoubleToInteger(number));
2506}
2507
2508
2509static Object* Runtime_NumberToJSUint32(Arguments args) {
2510 NoHandleAllocation ha;
2511 ASSERT(args.length() == 1);
2512
2513 Object* obj = args[0];
2514 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2515 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2516 return Heap::NumberFromUint32(number);
2517}
2518
2519
2520static Object* Runtime_NumberToJSInt32(Arguments args) {
2521 NoHandleAllocation ha;
2522 ASSERT(args.length() == 1);
2523
2524 Object* obj = args[0];
2525 if (obj->IsSmi()) return obj;
2526 CONVERT_DOUBLE_CHECKED(number, obj);
2527 return Heap::NumberFromInt32(DoubleToInt32(number));
2528}
2529
2530
2531static Object* Runtime_NumberAdd(Arguments args) {
2532 NoHandleAllocation ha;
2533 ASSERT(args.length() == 2);
2534
2535 CONVERT_DOUBLE_CHECKED(x, args[0]);
2536 CONVERT_DOUBLE_CHECKED(y, args[1]);
2537 return Heap::AllocateHeapNumber(x + y);
2538}
2539
2540
2541static Object* Runtime_NumberSub(Arguments args) {
2542 NoHandleAllocation ha;
2543 ASSERT(args.length() == 2);
2544
2545 CONVERT_DOUBLE_CHECKED(x, args[0]);
2546 CONVERT_DOUBLE_CHECKED(y, args[1]);
2547 return Heap::AllocateHeapNumber(x - y);
2548}
2549
2550
2551static Object* Runtime_NumberMul(Arguments args) {
2552 NoHandleAllocation ha;
2553 ASSERT(args.length() == 2);
2554
2555 CONVERT_DOUBLE_CHECKED(x, args[0]);
2556 CONVERT_DOUBLE_CHECKED(y, args[1]);
2557 return Heap::AllocateHeapNumber(x * y);
2558}
2559
2560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002561static Object* Runtime_NumberUnaryMinus(Arguments args) {
2562 NoHandleAllocation ha;
2563 ASSERT(args.length() == 1);
2564
2565 CONVERT_DOUBLE_CHECKED(x, args[0]);
2566 return Heap::AllocateHeapNumber(-x);
2567}
2568
2569
2570static Object* Runtime_NumberDiv(Arguments args) {
2571 NoHandleAllocation ha;
2572 ASSERT(args.length() == 2);
2573
2574 CONVERT_DOUBLE_CHECKED(x, args[0]);
2575 CONVERT_DOUBLE_CHECKED(y, args[1]);
2576 return Heap::NewNumberFromDouble(x / y);
2577}
2578
2579
2580static Object* Runtime_NumberMod(Arguments args) {
2581 NoHandleAllocation ha;
2582 ASSERT(args.length() == 2);
2583
2584 CONVERT_DOUBLE_CHECKED(x, args[0]);
2585 CONVERT_DOUBLE_CHECKED(y, args[1]);
2586
2587#ifdef WIN32
2588 // Workaround MS fmod bugs. ECMA-262 says:
2589 // dividend is finite and divisor is an infinity => result equals dividend
2590 // dividend is a zero and divisor is nonzero finite => result equals dividend
2591 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2592 !(x == 0 && (y != 0 && isfinite(y))))
2593#endif
2594 x = fmod(x, y);
2595 // NewNumberFromDouble may return a Smi instead of a Number object
2596 return Heap::NewNumberFromDouble(x);
2597}
2598
2599
2600static Object* Runtime_StringAdd(Arguments args) {
2601 NoHandleAllocation ha;
2602 ASSERT(args.length() == 2);
2603
2604 CONVERT_CHECKED(String, str1, args[0]);
2605 CONVERT_CHECKED(String, str2, args[1]);
2606 int len1 = str1->length();
2607 int len2 = str2->length();
2608 if (len1 == 0) return str2;
2609 if (len2 == 0) return str1;
2610 int length_sum = len1 + len2;
2611 // Make sure that an out of memory exception is thrown if the length
2612 // of the new cons string is too large to fit in a Smi.
2613 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2614 Top::context()->mark_out_of_memory();
2615 return Failure::OutOfMemoryException();
2616 }
2617 return Heap::AllocateConsString(str1, str2);
2618}
2619
2620
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002621template<typename sinkchar>
2622static inline void StringBuilderConcatHelper(String* special,
2623 sinkchar* sink,
2624 FixedArray* fixed_array,
2625 int array_length) {
2626 int position = 0;
2627 for (int i = 0; i < array_length; i++) {
2628 Object* element = fixed_array->get(i);
2629 if (element->IsSmi()) {
2630 int len = Smi::cast(element)->value();
2631 int pos = len >> 11;
2632 len &= 0x7ff;
2633 String::WriteToFlat(special, sink + position, pos, pos + len);
2634 position += len;
2635 } else {
2636 String* string = String::cast(element);
2637 int element_length = string->length();
2638 String::WriteToFlat(string, sink + position, 0, element_length);
2639 position += element_length;
2640 }
2641 }
2642}
2643
2644
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645static Object* Runtime_StringBuilderConcat(Arguments args) {
2646 NoHandleAllocation ha;
2647 ASSERT(args.length() == 2);
2648 CONVERT_CHECKED(JSArray, array, args[0]);
2649 CONVERT_CHECKED(String, special, args[1]);
2650 int special_length = special->length();
2651 Object* smi_array_length = array->length();
2652 if (!smi_array_length->IsSmi()) {
2653 Top::context()->mark_out_of_memory();
2654 return Failure::OutOfMemoryException();
2655 }
2656 int array_length = Smi::cast(smi_array_length)->value();
2657 if (!array->HasFastElements()) {
2658 return Top::Throw(Heap::illegal_argument_symbol());
2659 }
2660 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002661 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002662 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664
2665 if (array_length == 0) {
2666 return Heap::empty_string();
2667 } else if (array_length == 1) {
2668 Object* first = fixed_array->get(0);
2669 if (first->IsString()) return first;
2670 }
2671
ager@chromium.org7c537e22008-10-16 08:43:32 +00002672 bool ascii = special->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 int position = 0;
2674 for (int i = 0; i < array_length; i++) {
2675 Object* elt = fixed_array->get(i);
2676 if (elt->IsSmi()) {
2677 int len = Smi::cast(elt)->value();
2678 int pos = len >> 11;
2679 len &= 0x7ff;
2680 if (pos + len > special_length) {
2681 return Top::Throw(Heap::illegal_argument_symbol());
2682 }
2683 position += len;
2684 } else if (elt->IsString()) {
2685 String* element = String::cast(elt);
2686 int element_length = element->length();
2687 if (!Smi::IsValid(element_length + position)) {
2688 Top::context()->mark_out_of_memory();
2689 return Failure::OutOfMemoryException();
2690 }
2691 position += element_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002692 if (ascii && !element->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695 } else {
2696 return Top::Throw(Heap::illegal_argument_symbol());
2697 }
2698 }
2699
2700 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 if (ascii) {
2704 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002705 if (object->IsFailure()) return object;
2706 SeqAsciiString* answer = SeqAsciiString::cast(object);
2707 StringBuilderConcatHelper(special,
2708 answer->GetChars(),
2709 fixed_array,
2710 array_length);
2711 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 } else {
2713 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002714 if (object->IsFailure()) return object;
2715 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2716 StringBuilderConcatHelper(special,
2717 answer->GetChars(),
2718 fixed_array,
2719 array_length);
2720 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002722}
2723
2724
2725static Object* Runtime_NumberOr(Arguments args) {
2726 NoHandleAllocation ha;
2727 ASSERT(args.length() == 2);
2728
2729 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2730 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2731 return Heap::NumberFromInt32(x | y);
2732}
2733
2734
2735static Object* Runtime_NumberAnd(Arguments args) {
2736 NoHandleAllocation ha;
2737 ASSERT(args.length() == 2);
2738
2739 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2740 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2741 return Heap::NumberFromInt32(x & y);
2742}
2743
2744
2745static Object* Runtime_NumberXor(Arguments args) {
2746 NoHandleAllocation ha;
2747 ASSERT(args.length() == 2);
2748
2749 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2750 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2751 return Heap::NumberFromInt32(x ^ y);
2752}
2753
2754
2755static Object* Runtime_NumberNot(Arguments args) {
2756 NoHandleAllocation ha;
2757 ASSERT(args.length() == 1);
2758
2759 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2760 return Heap::NumberFromInt32(~x);
2761}
2762
2763
2764static Object* Runtime_NumberShl(Arguments args) {
2765 NoHandleAllocation ha;
2766 ASSERT(args.length() == 2);
2767
2768 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2769 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2770 return Heap::NumberFromInt32(x << (y & 0x1f));
2771}
2772
2773
2774static Object* Runtime_NumberShr(Arguments args) {
2775 NoHandleAllocation ha;
2776 ASSERT(args.length() == 2);
2777
2778 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2779 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2780 return Heap::NumberFromUint32(x >> (y & 0x1f));
2781}
2782
2783
2784static Object* Runtime_NumberSar(Arguments args) {
2785 NoHandleAllocation ha;
2786 ASSERT(args.length() == 2);
2787
2788 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2789 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2790 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2791}
2792
2793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794static Object* Runtime_NumberEquals(Arguments args) {
2795 NoHandleAllocation ha;
2796 ASSERT(args.length() == 2);
2797
2798 CONVERT_DOUBLE_CHECKED(x, args[0]);
2799 CONVERT_DOUBLE_CHECKED(y, args[1]);
2800 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2801 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2802 if (x == y) return Smi::FromInt(EQUAL);
2803 Object* result;
2804 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2805 result = Smi::FromInt(EQUAL);
2806 } else {
2807 result = Smi::FromInt(NOT_EQUAL);
2808 }
2809 return result;
2810}
2811
2812
2813static Object* Runtime_StringEquals(Arguments args) {
2814 NoHandleAllocation ha;
2815 ASSERT(args.length() == 2);
2816
2817 CONVERT_CHECKED(String, x, args[0]);
2818 CONVERT_CHECKED(String, y, args[1]);
2819
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002820 bool not_equal = !x->Equals(y);
2821 // This is slightly convoluted because the value that signifies
2822 // equality is 0 and inequality is 1 so we have to negate the result
2823 // from String::Equals.
2824 ASSERT(not_equal == 0 || not_equal == 1);
2825 STATIC_CHECK(EQUAL == 0);
2826 STATIC_CHECK(NOT_EQUAL == 1);
2827 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828}
2829
2830
2831static Object* Runtime_NumberCompare(Arguments args) {
2832 NoHandleAllocation ha;
2833 ASSERT(args.length() == 3);
2834
2835 CONVERT_DOUBLE_CHECKED(x, args[0]);
2836 CONVERT_DOUBLE_CHECKED(y, args[1]);
2837 if (isnan(x) || isnan(y)) return args[2];
2838 if (x == y) return Smi::FromInt(EQUAL);
2839 if (isless(x, y)) return Smi::FromInt(LESS);
2840 return Smi::FromInt(GREATER);
2841}
2842
2843
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002844// Compare two Smis as if they were converted to strings and then
2845// compared lexicographically.
2846static Object* Runtime_SmiLexicographicCompare(Arguments args) {
2847 NoHandleAllocation ha;
2848 ASSERT(args.length() == 2);
2849
2850 // Arrays for the individual characters of the two Smis. Smis are
2851 // 31 bit integers and 10 decimal digits are therefore enough.
2852 static int x_elms[10];
2853 static int y_elms[10];
2854
2855 // Extract the integer values from the Smis.
2856 CONVERT_CHECKED(Smi, x, args[0]);
2857 CONVERT_CHECKED(Smi, y, args[1]);
2858 int x_value = x->value();
2859 int y_value = y->value();
2860
2861 // If the integers are equal so are the string representations.
2862 if (x_value == y_value) return Smi::FromInt(EQUAL);
2863
2864 // If one of the integers are zero the normal integer order is the
2865 // same as the lexicographic order of the string representations.
2866 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
2867
2868 // If only one of the intergers is negative the negative number is
2869 // smallest because the char code of '-' is less than the char code
2870 // of any digit. Otherwise, we make both values positive.
2871 if (x_value < 0 || y_value < 0) {
2872 if (y_value >= 0) return Smi::FromInt(LESS);
2873 if (x_value >= 0) return Smi::FromInt(GREATER);
2874 x_value = -x_value;
2875 y_value = -y_value;
2876 }
2877
2878 // Convert the integers to arrays of their decimal digits.
2879 int x_index = 0;
2880 int y_index = 0;
2881 while (x_value > 0) {
2882 x_elms[x_index++] = x_value % 10;
2883 x_value /= 10;
2884 }
2885 while (y_value > 0) {
2886 y_elms[y_index++] = y_value % 10;
2887 y_value /= 10;
2888 }
2889
2890 // Loop through the arrays of decimal digits finding the first place
2891 // where they differ.
2892 while (--x_index >= 0 && --y_index >= 0) {
2893 int diff = x_elms[x_index] - y_elms[y_index];
2894 if (diff != 0) return Smi::FromInt(diff);
2895 }
2896
2897 // If one array is a suffix of the other array, the longest array is
2898 // the representation of the largest of the Smis in the
2899 // lexicographic ordering.
2900 return Smi::FromInt(x_index - y_index);
2901}
2902
2903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904static Object* Runtime_StringCompare(Arguments args) {
2905 NoHandleAllocation ha;
2906 ASSERT(args.length() == 2);
2907
2908 CONVERT_CHECKED(String, x, args[0]);
2909 CONVERT_CHECKED(String, y, args[1]);
2910
2911 // A few fast case tests before we flatten.
2912 if (x == y) return Smi::FromInt(EQUAL);
2913 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002914 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002915 return Smi::FromInt(GREATER);
2916 } else if (x->length() == 0) {
2917 return Smi::FromInt(LESS);
2918 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002919
2920 int d = x->Get(0) - y->Get(0);
2921 if (d < 0) return Smi::FromInt(LESS);
2922 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923
2924 x->TryFlatten();
2925 y->TryFlatten();
2926
2927 static StringInputBuffer bufx;
2928 static StringInputBuffer bufy;
2929 bufx.Reset(x);
2930 bufy.Reset(y);
2931 while (bufx.has_more() && bufy.has_more()) {
2932 int d = bufx.GetNext() - bufy.GetNext();
2933 if (d < 0) return Smi::FromInt(LESS);
2934 else if (d > 0) return Smi::FromInt(GREATER);
2935 }
2936
2937 // x is (non-trivial) prefix of y:
2938 if (bufy.has_more()) return Smi::FromInt(LESS);
2939 // y is prefix of x:
2940 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2941}
2942
2943
2944static Object* Runtime_Math_abs(Arguments args) {
2945 NoHandleAllocation ha;
2946 ASSERT(args.length() == 1);
2947
2948 CONVERT_DOUBLE_CHECKED(x, args[0]);
2949 return Heap::AllocateHeapNumber(fabs(x));
2950}
2951
2952
2953static Object* Runtime_Math_acos(Arguments args) {
2954 NoHandleAllocation ha;
2955 ASSERT(args.length() == 1);
2956
2957 CONVERT_DOUBLE_CHECKED(x, args[0]);
2958 return Heap::AllocateHeapNumber(acos(x));
2959}
2960
2961
2962static Object* Runtime_Math_asin(Arguments args) {
2963 NoHandleAllocation ha;
2964 ASSERT(args.length() == 1);
2965
2966 CONVERT_DOUBLE_CHECKED(x, args[0]);
2967 return Heap::AllocateHeapNumber(asin(x));
2968}
2969
2970
2971static Object* Runtime_Math_atan(Arguments args) {
2972 NoHandleAllocation ha;
2973 ASSERT(args.length() == 1);
2974
2975 CONVERT_DOUBLE_CHECKED(x, args[0]);
2976 return Heap::AllocateHeapNumber(atan(x));
2977}
2978
2979
2980static Object* Runtime_Math_atan2(Arguments args) {
2981 NoHandleAllocation ha;
2982 ASSERT(args.length() == 2);
2983
2984 CONVERT_DOUBLE_CHECKED(x, args[0]);
2985 CONVERT_DOUBLE_CHECKED(y, args[1]);
2986 double result;
2987 if (isinf(x) && isinf(y)) {
2988 // Make sure that the result in case of two infinite arguments
2989 // is a multiple of Pi / 4. The sign of the result is determined
2990 // by the first argument (x) and the sign of the second argument
2991 // determines the multiplier: one or three.
2992 static double kPiDividedBy4 = 0.78539816339744830962;
2993 int multiplier = (x < 0) ? -1 : 1;
2994 if (y < 0) multiplier *= 3;
2995 result = multiplier * kPiDividedBy4;
2996 } else {
2997 result = atan2(x, y);
2998 }
2999 return Heap::AllocateHeapNumber(result);
3000}
3001
3002
3003static Object* Runtime_Math_ceil(Arguments args) {
3004 NoHandleAllocation ha;
3005 ASSERT(args.length() == 1);
3006
3007 CONVERT_DOUBLE_CHECKED(x, args[0]);
3008 return Heap::NumberFromDouble(ceiling(x));
3009}
3010
3011
3012static Object* Runtime_Math_cos(Arguments args) {
3013 NoHandleAllocation ha;
3014 ASSERT(args.length() == 1);
3015
3016 CONVERT_DOUBLE_CHECKED(x, args[0]);
3017 return Heap::AllocateHeapNumber(cos(x));
3018}
3019
3020
3021static Object* Runtime_Math_exp(Arguments args) {
3022 NoHandleAllocation ha;
3023 ASSERT(args.length() == 1);
3024
3025 CONVERT_DOUBLE_CHECKED(x, args[0]);
3026 return Heap::AllocateHeapNumber(exp(x));
3027}
3028
3029
3030static Object* Runtime_Math_floor(Arguments args) {
3031 NoHandleAllocation ha;
3032 ASSERT(args.length() == 1);
3033
3034 CONVERT_DOUBLE_CHECKED(x, args[0]);
3035 return Heap::NumberFromDouble(floor(x));
3036}
3037
3038
3039static Object* Runtime_Math_log(Arguments args) {
3040 NoHandleAllocation ha;
3041 ASSERT(args.length() == 1);
3042
3043 CONVERT_DOUBLE_CHECKED(x, args[0]);
3044 return Heap::AllocateHeapNumber(log(x));
3045}
3046
3047
3048static Object* Runtime_Math_pow(Arguments args) {
3049 NoHandleAllocation ha;
3050 ASSERT(args.length() == 2);
3051
3052 CONVERT_DOUBLE_CHECKED(x, args[0]);
3053 CONVERT_DOUBLE_CHECKED(y, args[1]);
3054 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3055 return Heap::nan_value();
3056 } else if (y == 0) {
3057 return Smi::FromInt(1);
3058 } else {
3059 return Heap::AllocateHeapNumber(pow(x, y));
3060 }
3061}
3062
3063// Returns a number value with positive sign, greater than or equal to
3064// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003065static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003067 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003068
3069 // To get much better precision, we combine the results of two
3070 // invocations of random(). The result is computed by normalizing a
3071 // double in the range [0, RAND_MAX + 1) obtained by adding the
3072 // high-order bits in the range [0, RAND_MAX] with the low-order
3073 // bits in the range [0, 1).
3074 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
3075 double hi = static_cast<double>(random());
3076 double result = (hi + lo) / (RAND_MAX + 1.0);
3077 ASSERT(result >= 0 && result < 1);
3078 return Heap::AllocateHeapNumber(result);
3079}
3080
3081
3082static Object* Runtime_Math_round(Arguments args) {
3083 NoHandleAllocation ha;
3084 ASSERT(args.length() == 1);
3085
3086 CONVERT_DOUBLE_CHECKED(x, args[0]);
3087 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3088 return Heap::NumberFromDouble(floor(x + 0.5));
3089}
3090
3091
3092static Object* Runtime_Math_sin(Arguments args) {
3093 NoHandleAllocation ha;
3094 ASSERT(args.length() == 1);
3095
3096 CONVERT_DOUBLE_CHECKED(x, args[0]);
3097 return Heap::AllocateHeapNumber(sin(x));
3098}
3099
3100
3101static Object* Runtime_Math_sqrt(Arguments args) {
3102 NoHandleAllocation ha;
3103 ASSERT(args.length() == 1);
3104
3105 CONVERT_DOUBLE_CHECKED(x, args[0]);
3106 return Heap::AllocateHeapNumber(sqrt(x));
3107}
3108
3109
3110static Object* Runtime_Math_tan(Arguments args) {
3111 NoHandleAllocation ha;
3112 ASSERT(args.length() == 1);
3113
3114 CONVERT_DOUBLE_CHECKED(x, args[0]);
3115 return Heap::AllocateHeapNumber(tan(x));
3116}
3117
3118
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003119// The NewArguments function is only used when constructing the
3120// arguments array when calling non-functions from JavaScript in
3121// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122static Object* Runtime_NewArguments(Arguments args) {
3123 NoHandleAllocation ha;
3124 ASSERT(args.length() == 1);
3125
3126 // ECMA-262, 3rd., 10.1.8, p.39
3127 CONVERT_CHECKED(JSFunction, callee, args[0]);
3128
3129 // Compute the frame holding the arguments.
3130 JavaScriptFrameIterator it;
3131 it.AdvanceToArgumentsFrame();
3132 JavaScriptFrame* frame = it.frame();
3133
3134 const int length = frame->GetProvidedParametersCount();
3135 Object* result = Heap::AllocateArgumentsObject(callee, length);
3136 if (result->IsFailure()) return result;
3137 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
3138 ASSERT(array->length() == length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003139 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003140 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003141 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142 }
3143 return result;
3144}
3145
3146
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003147static Object* Runtime_NewArgumentsFast(Arguments args) {
3148 NoHandleAllocation ha;
3149 ASSERT(args.length() == 3);
3150
3151 JSFunction* callee = JSFunction::cast(args[0]);
3152 Object** parameters = reinterpret_cast<Object**>(args[1]);
3153 const int length = Smi::cast(args[2])->value();
3154
3155 Object* result = Heap::AllocateArgumentsObject(callee, length);
3156 if (result->IsFailure()) return result;
3157 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
3158 ASSERT(array->length() == length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003159 WriteBarrierMode mode = array->GetWriteBarrierMode();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003160 for (int i = 0; i < length; i++) {
3161 array->set(i, *--parameters, mode);
3162 }
3163 return result;
3164}
3165
3166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003167static Object* Runtime_NewClosure(Arguments args) {
3168 HandleScope scope;
3169 ASSERT(args.length() == 2);
3170 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3171 CONVERT_ARG_CHECKED(Context, context, 1);
3172
3173 Handle<JSFunction> result =
3174 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3175 return *result;
3176}
3177
3178
3179static Object* Runtime_NewObject(Arguments args) {
3180 NoHandleAllocation ha;
3181 ASSERT(args.length() == 1);
3182
3183 Object* constructor = args[0];
3184 if (constructor->IsJSFunction()) {
3185 JSFunction* function = JSFunction::cast(constructor);
3186
3187 // Handle steping into constructors.
3188 if (Debug::StepInActive()) {
3189 StackFrameIterator it;
3190 it.Advance();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003191 ASSERT(it.frame()->is_construct());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003192 it.Advance();
3193 if (it.frame()->fp() == Debug::step_in_fp()) {
3194 HandleScope scope;
3195 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
3196 }
3197 }
3198
3199 if (function->has_initial_map() &&
3200 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3201 // The 'Function' function ignores the receiver object when
3202 // called using 'new' and creates a new JSFunction object that
3203 // is returned. The receiver object is only used for error
3204 // reporting if an error occurs when constructing the new
3205 // JSFunction. AllocateJSObject should not be used to allocate
3206 // JSFunctions since it does not properly initialize the shared
3207 // part of the function. Since the receiver is ignored anyway,
3208 // we use the global object as the receiver instead of a new
3209 // JSFunction object. This way, errors are reported the same
3210 // way whether or not 'Function' is called using 'new'.
3211 return Top::context()->global();
3212 }
3213 return Heap::AllocateJSObject(function);
3214 }
3215
3216 HandleScope scope;
3217 Handle<Object> cons(constructor);
3218 // The constructor is not a function; throw a type error.
3219 Handle<Object> type_error =
3220 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3221 return Top::Throw(*type_error);
3222}
3223
3224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225static Object* Runtime_LazyCompile(Arguments args) {
3226 HandleScope scope;
3227 ASSERT(args.length() == 1);
3228
3229 Handle<JSFunction> function = args.at<JSFunction>(0);
3230#ifdef DEBUG
3231 if (FLAG_trace_lazy) {
3232 PrintF("[lazy: ");
3233 function->shared()->name()->Print();
3234 PrintF("]\n");
3235 }
3236#endif
3237
3238 // Compile the target function.
3239 ASSERT(!function->is_compiled());
3240 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3241 return Failure::Exception();
3242 }
3243
3244 return function->code();
3245}
3246
3247
3248static Object* Runtime_GetCalledFunction(Arguments args) {
3249 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003250 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251 StackFrameIterator it;
3252 // Get past the JS-to-C exit frame.
3253 ASSERT(it.frame()->is_exit());
3254 it.Advance();
3255 // Get past the CALL_NON_FUNCTION activation frame.
3256 ASSERT(it.frame()->is_java_script());
3257 it.Advance();
3258 // Argument adaptor frames do not copy the function; we have to skip
3259 // past them to get to the real calling frame.
3260 if (it.frame()->is_arguments_adaptor()) it.Advance();
3261 // Get the function from the top of the expression stack of the
3262 // calling frame.
3263 StandardFrame* frame = StandardFrame::cast(it.frame());
3264 int index = frame->ComputeExpressionsCount() - 1;
3265 Object* result = frame->GetExpression(index);
3266 return result;
3267}
3268
3269
3270static Object* Runtime_GetFunctionDelegate(Arguments args) {
3271 HandleScope scope;
3272 ASSERT(args.length() == 1);
3273 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3274 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3275}
3276
3277
3278static Object* Runtime_NewContext(Arguments args) {
3279 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003280 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003281
kasper.lund7276f142008-07-30 08:49:36 +00003282 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003283 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3284 Object* result = Heap::AllocateFunctionContext(length, function);
3285 if (result->IsFailure()) return result;
3286
3287 Top::set_context(Context::cast(result));
3288
kasper.lund7276f142008-07-30 08:49:36 +00003289 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290}
3291
3292
3293static Object* Runtime_PushContext(Arguments args) {
3294 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003295 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296
3297 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00003298 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003299 if (!object->IsJSObject()) {
3300 object = object->ToObject();
3301 if (object->IsFailure()) {
3302 if (!Failure::cast(object)->IsInternalError()) return object;
3303 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00003304 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003305 Handle<Object> result =
3306 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3307 return Top::Throw(*result);
3308 }
3309 }
3310
3311 Object* result =
3312 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
3313 if (result->IsFailure()) return result;
3314
3315 Top::set_context(Context::cast(result));
3316
kasper.lund7276f142008-07-30 08:49:36 +00003317 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003318}
3319
3320
3321static Object* Runtime_LookupContext(Arguments args) {
3322 HandleScope scope;
3323 ASSERT(args.length() == 2);
3324
3325 CONVERT_ARG_CHECKED(Context, context, 0);
3326 CONVERT_ARG_CHECKED(String, name, 1);
3327
3328 int index;
3329 PropertyAttributes attributes;
3330 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003331 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003332 context->Lookup(name, flags, &index, &attributes);
3333
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003334 if (index < 0 && *holder != NULL) {
3335 ASSERT(holder->IsJSObject());
3336 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003337 }
3338
3339 // No intermediate context found. Use global object by default.
3340 return Top::context()->global();
3341}
3342
3343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344// A mechanism to return pairs of Object*'s. This is somewhat
3345// compiler-dependent as it assumes that a 64-bit value (a long long)
3346// is returned via two registers (edx:eax on ia32). Both the ia32 and
3347// arm platform support this; it is mostly an issue of "coaxing" the
3348// compiler to do the right thing.
3349//
3350// TODO(1236026): This is a non-portable hack that should be removed.
3351typedef uint64_t ObjPair;
3352ObjPair MakePair(Object* x, Object* y) {
3353 return reinterpret_cast<uint32_t>(x) |
3354 (reinterpret_cast<ObjPair>(y) << 32);
3355}
3356
3357
3358static Object* Unhole(Object* x, PropertyAttributes attributes) {
3359 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3360 USE(attributes);
3361 return x->IsTheHole() ? Heap::undefined_value() : x;
3362}
3363
3364
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003365static Object* ComputeContextSlotReceiver(Object* holder) {
3366 // If the "property" we were looking for is a local variable or an
3367 // argument in a context, the receiver is the global object; see
3368 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3369 HeapObject* object = HeapObject::cast(holder);
3370 Context* top = Top::context();
3371 if (holder->IsContext()) return top->global()->global_receiver();
3372
3373 // TODO(125): Find a better - and faster way - of checking for
3374 // arguments and context extension objects. This kinda sucks.
3375 JSFunction* context_extension_function =
3376 top->global_context()->context_extension_function();
3377 JSObject* arguments_boilerplate =
3378 top->global_context()->arguments_boilerplate();
3379 JSFunction* arguments_function =
3380 JSFunction::cast(arguments_boilerplate->map()->constructor());
3381 // If the holder is an arguments object or a context extension then the
3382 // receiver is also the global object;
3383 Object* constructor = HeapObject::cast(holder)->map()->constructor();
3384 if (constructor == context_extension_function ||
3385 constructor == arguments_function) {
3386 return Top::context()->global()->global_receiver();
3387 }
3388
3389 // If the holder is a global object, we have to be careful to wrap
3390 // it in its proxy if necessary.
3391 if (object->IsGlobalObject()) {
3392 return GlobalObject::cast(object)->global_receiver();
3393 } else {
3394 return object;
3395 }
3396}
3397
3398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
3400 HandleScope scope;
3401 ASSERT(args.length() == 2);
3402
3403 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
3404 Handle<Context> context = args.at<Context>(0);
3405 Handle<String> name(String::cast(args[1]));
3406
3407 int index;
3408 PropertyAttributes attributes;
3409 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003410 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 context->Lookup(name, flags, &index, &attributes);
3412
3413 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003414 Handle<Object> receiver =
3415 Handle<Object>(ComputeContextSlotReceiver(*holder));
3416 Handle<Object> value;
3417 if (holder->IsContext()) {
3418 value = Handle<Object>(Context::cast(*holder)->get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003420 // Arguments object.
3421 value = Handle<Object>(JSObject::cast(*holder)->GetElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003422 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003423 return MakePair(Unhole(*value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 }
3425
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003426 if (*holder != NULL) {
3427 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
3428 // Note: As of 5/29/2008, GetProperty does the "unholing" and so
3429 // this call here is redundant. We left it anyway, to be explicit;
3430 // also it's not clear why GetProperty should do the unholing in
3431 // the first place.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003432 return MakePair(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003433 Unhole(Handle<JSObject>::cast(holder)->GetProperty(*name),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434 attributes),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003435 ComputeContextSlotReceiver(*holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 }
3437
3438 if (throw_error) {
3439 // The property doesn't exist - throw exception.
3440 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003441 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 return MakePair(Top::Throw(*reference_error), NULL);
3443 } else {
3444 // The property doesn't exist - return undefined
3445 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3446 }
3447}
3448
3449
3450static ObjPair Runtime_LoadContextSlot(Arguments args) {
3451 return LoadContextSlotHelper(args, true);
3452}
3453
3454
3455static ObjPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
3456 return LoadContextSlotHelper(args, false);
3457}
3458
3459
3460static Object* Runtime_StoreContextSlot(Arguments args) {
3461 HandleScope scope;
3462 ASSERT(args.length() == 3);
3463
3464 Handle<Object> value(args[0]);
3465 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003466 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003467
3468 int index;
3469 PropertyAttributes attributes;
3470 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003471 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 context->Lookup(name, flags, &index, &attributes);
3473
3474 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003475 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476 // Ignore if read_only variable.
3477 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003478 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479 }
3480 } else {
3481 ASSERT((attributes & READ_ONLY) == 0);
3482 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003483 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 USE(result);
3485 ASSERT(!result->IsFailure());
3486 }
3487 return *value;
3488 }
3489
3490 // Slow case: The property is not in a FixedArray context.
3491 // It is either in an JSObject extension context or it was not found.
3492 Handle<JSObject> context_ext;
3493
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003494 if (*holder != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003496 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003497 } else {
3498 // The property was not found. It needs to be stored in the global context.
3499 ASSERT(attributes == ABSENT);
3500 attributes = NONE;
3501 context_ext = Handle<JSObject>(Top::context()->global());
3502 }
3503
3504 // Set the property, but ignore if read_only variable.
3505 if ((attributes & READ_ONLY) == 0) {
3506 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3507 if (set.is_null()) {
3508 // Failure::Exception is converted to a null handle in the
3509 // handle-based methods such as SetProperty. We therefore need
3510 // to convert null handles back to exceptions.
3511 ASSERT(Top::has_pending_exception());
3512 return Failure::Exception();
3513 }
3514 }
3515 return *value;
3516}
3517
3518
3519static Object* Runtime_Throw(Arguments args) {
3520 HandleScope scope;
3521 ASSERT(args.length() == 1);
3522
3523 return Top::Throw(args[0]);
3524}
3525
3526
3527static Object* Runtime_ReThrow(Arguments args) {
3528 HandleScope scope;
3529 ASSERT(args.length() == 1);
3530
3531 return Top::ReThrow(args[0]);
3532}
3533
3534
3535static Object* Runtime_ThrowReferenceError(Arguments args) {
3536 HandleScope scope;
3537 ASSERT(args.length() == 1);
3538
3539 Handle<Object> name(args[0]);
3540 Handle<Object> reference_error =
3541 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3542 return Top::Throw(*reference_error);
3543}
3544
3545
3546static Object* Runtime_StackOverflow(Arguments args) {
3547 NoHandleAllocation na;
3548 return Top::StackOverflow();
3549}
3550
3551
3552static Object* RuntimePreempt(Arguments args) {
3553 // Clear the preempt request flag.
3554 StackGuard::Continue(PREEMPT);
3555
3556 ContextSwitcher::PreemptionReceived();
3557
3558 {
3559 v8::Unlocker unlocker;
3560 Thread::YieldCPU();
3561 }
3562
3563 return Heap::undefined_value();
3564}
3565
3566
3567static Object* Runtime_DebugBreak(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003568 // Just continue if breaks are disabled.
3569 if (Debug::disable_break()) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003570 return args[0];
3571 }
3572
kasper.lund7276f142008-07-30 08:49:36 +00003573 // Don't break in system functions. If the current function is
3574 // either in the builtins object of some context or is in the debug
3575 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003576 JavaScriptFrameIterator it;
3577 JavaScriptFrame* frame = it.frame();
3578 Object* fun = frame->function();
3579 if (fun->IsJSFunction()) {
3580 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3581 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
3582 return args[0];
3583 }
3584 }
3585
3586 // Clear the debug request flag.
3587 StackGuard::Continue(DEBUGBREAK);
3588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003590 // Enter the debugger. Just continue if we fail to enter the debugger.
3591 EnterDebugger debugger;
3592 if (debugger.FailedToEnter()) {
3593 return args[0];
3594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595
kasper.lund7276f142008-07-30 08:49:36 +00003596 // Notify the debug event listeners.
3597 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598
3599 // Return to continue execution.
3600 return args[0];
3601}
3602
3603
3604static Object* Runtime_StackGuard(Arguments args) {
3605 ASSERT(args.length() == 1);
3606
3607 // First check if this is a real stack overflow.
3608 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3609
3610 // If not real stack overflow the stack guard was used to interrupt
3611 // execution for another purpose.
3612 if (StackGuard::IsDebugBreak()) Runtime_DebugBreak(args);
3613 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3614 if (StackGuard::IsInterrupted()) {
3615 // interrupt
3616 StackGuard::Continue(INTERRUPT);
3617 return Top::StackOverflow();
3618 }
3619 return Heap::undefined_value();
3620}
3621
3622
3623// NOTE: These PrintXXX functions are defined for all builds (not just
3624// DEBUG builds) because we may want to be able to trace function
3625// calls in all modes.
3626static void PrintString(String* str) {
3627 // not uncommon to have empty strings
3628 if (str->length() > 0) {
3629 SmartPointer<char> s =
3630 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3631 PrintF("%s", *s);
3632 }
3633}
3634
3635
3636static void PrintObject(Object* obj) {
3637 if (obj->IsSmi()) {
3638 PrintF("%d", Smi::cast(obj)->value());
3639 } else if (obj->IsString() || obj->IsSymbol()) {
3640 PrintString(String::cast(obj));
3641 } else if (obj->IsNumber()) {
3642 PrintF("%g", obj->Number());
3643 } else if (obj->IsFailure()) {
3644 PrintF("<failure>");
3645 } else if (obj->IsUndefined()) {
3646 PrintF("<undefined>");
3647 } else if (obj->IsNull()) {
3648 PrintF("<null>");
3649 } else if (obj->IsTrue()) {
3650 PrintF("<true>");
3651 } else if (obj->IsFalse()) {
3652 PrintF("<false>");
3653 } else {
3654 PrintF("%p", obj);
3655 }
3656}
3657
3658
3659static int StackSize() {
3660 int n = 0;
3661 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3662 return n;
3663}
3664
3665
3666static void PrintTransition(Object* result) {
3667 // indentation
3668 { const int nmax = 80;
3669 int n = StackSize();
3670 if (n <= nmax)
3671 PrintF("%4d:%*s", n, n, "");
3672 else
3673 PrintF("%4d:%*s", n, nmax, "...");
3674 }
3675
3676 if (result == NULL) {
3677 // constructor calls
3678 JavaScriptFrameIterator it;
3679 JavaScriptFrame* frame = it.frame();
3680 if (frame->IsConstructor()) PrintF("new ");
3681 // function name
3682 Object* fun = frame->function();
3683 if (fun->IsJSFunction()) {
3684 PrintObject(JSFunction::cast(fun)->shared()->name());
3685 } else {
3686 PrintObject(fun);
3687 }
3688 // function arguments
3689 // (we are intentionally only printing the actually
3690 // supplied parameters, not all parameters required)
3691 PrintF("(this=");
3692 PrintObject(frame->receiver());
3693 const int length = frame->GetProvidedParametersCount();
3694 for (int i = 0; i < length; i++) {
3695 PrintF(", ");
3696 PrintObject(frame->GetParameter(i));
3697 }
3698 PrintF(") {\n");
3699
3700 } else {
3701 // function result
3702 PrintF("} -> ");
3703 PrintObject(result);
3704 PrintF("\n");
3705 }
3706}
3707
3708
3709static Object* Runtime_TraceEnter(Arguments args) {
3710 NoHandleAllocation ha;
3711 PrintTransition(NULL);
3712 return args[0]; // return TOS
3713}
3714
3715
3716static Object* Runtime_TraceExit(Arguments args) {
3717 NoHandleAllocation ha;
3718 PrintTransition(args[0]);
3719 return args[0]; // return TOS
3720}
3721
3722
3723static Object* Runtime_DebugPrint(Arguments args) {
3724 NoHandleAllocation ha;
3725 ASSERT(args.length() == 1);
3726
3727#ifdef DEBUG
3728 if (args[0]->IsString()) {
3729 // If we have a string, assume it's a code "marker"
3730 // and print some interesting cpu debugging info.
3731 JavaScriptFrameIterator it;
3732 JavaScriptFrame* frame = it.frame();
3733 PrintF("fp = %p, sp = %p, pp = %p: ",
3734 frame->fp(), frame->sp(), frame->pp());
3735 } else {
3736 PrintF("DebugPrint: ");
3737 }
3738 args[0]->Print();
3739#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003740 // ShortPrint is available in release mode. Print is not.
3741 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742#endif
3743 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003744 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745
3746 return args[0]; // return TOS
3747}
3748
3749
3750static Object* Runtime_DebugTrace(Arguments args) {
3751 ASSERT(args.length() == 1);
3752 NoHandleAllocation ha;
3753 Top::PrintStack();
3754 return args[0]; // return TOS
3755}
3756
3757
mads.s.ager31e71382008-08-13 09:32:07 +00003758static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003760 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761
3762 // According to ECMA-262, section 15.9.1, page 117, the precision of
3763 // the number in a Date object representing a particular instant in
3764 // time is milliseconds. Therefore, we floor the result of getting
3765 // the OS time.
3766 double millis = floor(OS::TimeCurrentMillis());
3767 return Heap::NumberFromDouble(millis);
3768}
3769
3770
3771static Object* Runtime_DateParseString(Arguments args) {
3772 HandleScope scope;
3773 ASSERT(args.length() == 1);
3774
3775 CONVERT_CHECKED(String, string_object, args[0]);
3776
3777 Handle<String> str(string_object);
3778 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3779 if (DateParser::Parse(*str, *output)) {
3780 return *Factory::NewJSArrayWithElements(output);
3781 } else {
3782 return *Factory::null_value();
3783 }
3784}
3785
3786
3787static Object* Runtime_DateLocalTimezone(Arguments args) {
3788 NoHandleAllocation ha;
3789 ASSERT(args.length() == 1);
3790
3791 CONVERT_DOUBLE_CHECKED(x, args[0]);
3792 char* zone = OS::LocalTimezone(x);
3793 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3794}
3795
3796
3797static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3798 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003799 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800
3801 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3802}
3803
3804
3805static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3806 NoHandleAllocation ha;
3807 ASSERT(args.length() == 1);
3808
3809 CONVERT_DOUBLE_CHECKED(x, args[0]);
3810 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3811}
3812
3813
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814static Object* Runtime_NumberIsFinite(Arguments args) {
3815 NoHandleAllocation ha;
3816 ASSERT(args.length() == 1);
3817
3818 CONVERT_DOUBLE_CHECKED(value, args[0]);
3819 Object* result;
3820 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3821 result = Heap::false_value();
3822 } else {
3823 result = Heap::true_value();
3824 }
3825 return result;
3826}
3827
3828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829static Object* EvalContext() {
3830 // The topmost JS frame belongs to the eval function which called
3831 // the CompileString runtime function. We need to unwind one level
3832 // to get to the caller of eval.
3833 StackFrameLocator locator;
3834 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3835
kasper.lund44510672008-07-25 07:37:58 +00003836 // TODO(900055): Right now we check if the caller of eval() supports
3837 // eval to determine if it's an aliased eval or not. This may not be
3838 // entirely correct in the unlikely case where a function uses both
3839 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 HandleScope scope;
3841 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003842 // Aliased eval: Evaluate in the global context of the eval
3843 // function to support aliased, cross environment evals.
3844 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 }
3846
3847 // Fetch the caller context from the frame.
3848 Handle<Context> caller(Context::cast(frame->context()));
3849
3850 // Check for eval() invocations that cross environments. Use the
3851 // context from the stack if evaluating in current environment.
3852 Handle<Context> target = Top::global_context();
3853 if (caller->global_context() == *target) return *caller;
3854
3855 // Compute a function closure that captures the calling context. We
3856 // need a function that has trivial scope info, since it is only
3857 // used to hold the context chain together.
3858 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3859 Factory::undefined_value());
3860 closure->set_context(*caller);
3861
3862 // Create a new adaptor context that has the target environment as
3863 // the extension object. This enables the evaluated code to see both
3864 // the current context with locals and everything and to see global
3865 // variables declared in the target global object. Furthermore, any
3866 // properties introduced with 'var' will be added to the target
3867 // global object because it is the extension object.
3868 Handle<Context> adaptor =
3869 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3870 adaptor->set_extension(target->global());
3871 return *adaptor;
3872}
3873
3874
3875static Object* Runtime_EvalReceiver(Arguments args) {
3876 StackFrameLocator locator;
3877 return locator.FindJavaScriptFrame(1)->receiver();
3878}
3879
3880
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003881static Object* Runtime_GlobalReceiver(Arguments args) {
3882 ASSERT(args.length() == 1);
3883 Object* global = args[0];
3884 if (!global->IsJSGlobalObject()) return Heap::null_value();
3885 return JSGlobalObject::cast(global)->global_receiver();
3886}
3887
3888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889static Object* Runtime_CompileString(Arguments args) {
3890 HandleScope scope;
ager@chromium.org236ad962008-09-25 09:45:57 +00003891 ASSERT(args.length() == 3);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003892 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00003893 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
3894 bool contextual = args[2]->IsTrue();
3895 RUNTIME_ASSERT(contextual || args[2]->IsFalse());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896
3897 // Compute the eval context.
3898 Handle<Context> context;
3899 if (contextual) {
3900 // Get eval context. May not be available if we are calling eval
3901 // through an alias, and the corresponding frame doesn't have a
3902 // proper eval context set up.
3903 Object* eval_context = EvalContext();
3904 if (eval_context->IsFailure()) return eval_context;
3905 context = Handle<Context>(Context::cast(eval_context));
3906 } else {
3907 context = Handle<Context>(Top::context()->global_context());
3908 }
3909
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003910
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003911 // Compile source string.
3912 bool is_global = context->IsGlobalContext();
3913 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00003914 Compiler::CompileEval(source, line_offset->value(), is_global);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003915 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 Handle<JSFunction> fun =
3917 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3918 return *fun;
3919}
3920
3921
3922static Object* Runtime_CompileScript(Arguments args) {
3923 HandleScope scope;
3924 ASSERT(args.length() == 4);
3925
3926 CONVERT_ARG_CHECKED(String, source, 0);
3927 CONVERT_ARG_CHECKED(String, script, 1);
3928 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3929 int line = line_attrs->value();
3930 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3931 int col = col_attrs->value();
3932 Handle<JSFunction> boilerplate =
3933 Compiler::Compile(source, script, line, col, NULL, NULL);
3934 if (boilerplate.is_null()) return Failure::Exception();
3935 Handle<JSFunction> fun =
3936 Factory::NewFunctionFromBoilerplate(boilerplate,
3937 Handle<Context>(Top::context()));
3938 return *fun;
3939}
3940
3941
3942static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3943 // This utility adjusts the property attributes for newly created Function
3944 // object ("new Function(...)") by changing the map.
3945 // All it does is changing the prototype property to enumerable
3946 // as specified in ECMA262, 15.3.5.2.
3947 HandleScope scope;
3948 ASSERT(args.length() == 1);
3949 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3950 ASSERT(func->map()->instance_type() ==
3951 Top::function_instance_map()->instance_type());
3952 ASSERT(func->map()->instance_size() ==
3953 Top::function_instance_map()->instance_size());
3954 func->set_map(*Top::function_instance_map());
3955 return *func;
3956}
3957
3958
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003959// Push an array unto an array of arrays if it is not already in the
3960// array. Returns true if the element was pushed on the stack and
3961// false otherwise.
3962static Object* Runtime_PushIfAbsent(Arguments args) {
3963 ASSERT(args.length() == 2);
3964 CONVERT_CHECKED(JSArray, array, args[0]);
3965 CONVERT_CHECKED(JSArray, element, args[1]);
3966 RUNTIME_ASSERT(array->HasFastElements());
3967 int length = Smi::cast(array->length())->value();
3968 FixedArray* elements = FixedArray::cast(array->elements());
3969 for (int i = 0; i < length; i++) {
3970 if (elements->get(i) == element) return Heap::false_value();
3971 }
3972 Object* obj = array->SetFastElement(length, element);
3973 if (obj->IsFailure()) return obj;
3974 return Heap::true_value();
3975}
3976
3977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978// This will not allocate (flatten the string), but it may run
3979// very slowly for very deeply nested ConsStrings. For debugging use only.
3980static Object* Runtime_GlobalPrint(Arguments args) {
3981 NoHandleAllocation ha;
3982 ASSERT(args.length() == 1);
3983
3984 CONVERT_CHECKED(String, string, args[0]);
3985 StringInputBuffer buffer(string);
3986 while (buffer.has_more()) {
3987 uint16_t character = buffer.GetNext();
3988 PrintF("%c", character);
3989 }
3990 return string;
3991}
3992
3993
3994static Object* Runtime_RemoveArrayHoles(Arguments args) {
3995 ASSERT(args.length() == 1);
3996 // Ignore the case if this is not a JSArray.
3997 if (!args[0]->IsJSArray()) return args[0];
3998 return JSArray::cast(args[0])->RemoveHoles();
3999}
4000
4001
4002// Move contents of argument 0 (an array) to argument 1 (an array)
4003static Object* Runtime_MoveArrayContents(Arguments args) {
4004 ASSERT(args.length() == 2);
4005 CONVERT_CHECKED(JSArray, from, args[0]);
4006 CONVERT_CHECKED(JSArray, to, args[1]);
4007 to->SetContent(FixedArray::cast(from->elements()));
4008 to->set_length(from->length());
4009 from->SetContent(Heap::empty_fixed_array());
4010 from->set_length(0);
4011 return to;
4012}
4013
4014
4015// How many elements does this array have?
4016static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4017 ASSERT(args.length() == 1);
4018 CONVERT_CHECKED(JSArray, array, args[0]);
4019 HeapObject* elements = array->elements();
4020 if (elements->IsDictionary()) {
4021 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4022 } else {
4023 return array->length();
4024 }
4025}
4026
4027
4028// Returns an array that tells you where in the [0, length) interval an array
4029// might have elements. Can either return keys or intervals. Keys can have
4030// gaps in (undefined). Intervals can also span over some undefined keys.
4031static Object* Runtime_GetArrayKeys(Arguments args) {
4032 ASSERT(args.length() == 2);
4033 HandleScope scope;
4034 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4035 Handle<JSArray> array(raw_array);
4036 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004037 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 // Create an array and get all the keys into it, then remove all the
4039 // keys that are not integers in the range 0 to length-1.
4040 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4041 int keys_length = keys->length();
4042 for (int i = 0; i < keys_length; i++) {
4043 Object* key = keys->get(i);
4044 uint32_t index;
4045 if (!Array::IndexFromObject(key, &index) || index >= length) {
4046 // Zap invalid keys.
4047 keys->set_undefined(i);
4048 }
4049 }
4050 return *Factory::NewJSArrayWithElements(keys);
4051 } else {
4052 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4053 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004054 single_interval->set(0,
4055 Smi::FromInt(-1),
4056 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 Handle<Object> length_object =
4058 Factory::NewNumber(static_cast<double>(length));
4059 single_interval->set(1, *length_object);
4060 return *Factory::NewJSArrayWithElements(single_interval);
4061 }
4062}
4063
4064
4065// DefineAccessor takes an optional final argument which is the
4066// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4067// to the way accessors are implemented, it is set for both the getter
4068// and setter on the first call to DefineAccessor and ignored on
4069// subsequent calls.
4070static Object* Runtime_DefineAccessor(Arguments args) {
4071 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4072 // Compute attributes.
4073 PropertyAttributes attributes = NONE;
4074 if (args.length() == 5) {
4075 CONVERT_CHECKED(Smi, attrs, args[4]);
4076 int value = attrs->value();
4077 // Only attribute bits should be set.
4078 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4079 attributes = static_cast<PropertyAttributes>(value);
4080 }
4081
4082 CONVERT_CHECKED(JSObject, obj, args[0]);
4083 CONVERT_CHECKED(String, name, args[1]);
4084 CONVERT_CHECKED(Smi, flag, args[2]);
4085 CONVERT_CHECKED(JSFunction, fun, args[3]);
4086 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4087}
4088
4089
4090static Object* Runtime_LookupAccessor(Arguments args) {
4091 ASSERT(args.length() == 3);
4092 CONVERT_CHECKED(JSObject, obj, args[0]);
4093 CONVERT_CHECKED(String, name, args[1]);
4094 CONVERT_CHECKED(Smi, flag, args[2]);
4095 return obj->LookupAccessor(name, flag->value() == 0);
4096}
4097
4098
4099// Helper functions for wrapping and unwrapping stack frame ids.
4100static Smi* WrapFrameId(StackFrame::Id id) {
4101 ASSERT(IsAligned(OffsetFrom(id), 4));
4102 return Smi::FromInt(id >> 2);
4103}
4104
4105
4106static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4107 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4108}
4109
4110
4111// Adds a JavaScript function as a debug event listener.
4112// args[0]: debug event listener function
4113// args[1]: object supplied during callback
4114static Object* Runtime_AddDebugEventListener(Arguments args) {
4115 ASSERT(args.length() == 2);
4116 // Convert the parameters to API objects to call the API function for adding
4117 // a JavaScript function as debug event listener.
4118 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4119 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4120 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
4121 v8::Debug::AddDebugEventListener(fun, data);
4122
4123 return Heap::undefined_value();
4124}
4125
4126
4127// Removes a JavaScript function debug event listener.
4128// args[0]: debug event listener function
4129static Object* Runtime_RemoveDebugEventListener(Arguments args) {
4130 ASSERT(args.length() == 1);
4131 // Convert the parameter to an API object to call the API function for
4132 // removing a JavaScript function debug event listener.
4133 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4134 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4135 v8::Debug::RemoveDebugEventListener(fun);
4136
4137 return Heap::undefined_value();
4138}
4139
4140
4141static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004142 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 StackGuard::DebugBreak();
4144 return Heap::undefined_value();
4145}
4146
4147
4148static Object* DebugLookupResultValue(LookupResult* result) {
4149 Object* value;
4150 switch (result->type()) {
4151 case NORMAL: {
4152 Dictionary* dict =
4153 JSObject::cast(result->holder())->property_dictionary();
4154 value = dict->ValueAt(result->GetDictionaryEntry());
4155 if (value->IsTheHole()) {
4156 return Heap::undefined_value();
4157 }
4158 return value;
4159 }
4160 case FIELD:
4161 value =
4162 JSObject::cast(
ager@chromium.org7c537e22008-10-16 08:43:32 +00004163 result->holder())->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 if (value->IsTheHole()) {
4165 return Heap::undefined_value();
4166 }
4167 return value;
4168 case CONSTANT_FUNCTION:
4169 return result->GetConstantFunction();
4170 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172 case MAP_TRANSITION:
4173 case CONSTANT_TRANSITION:
4174 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 return Heap::undefined_value();
4176 default:
4177 UNREACHABLE();
4178 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 return Heap::undefined_value();
4181}
4182
4183
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004184static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 HandleScope scope;
4186
4187 ASSERT(args.length() == 2);
4188
4189 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4190 CONVERT_ARG_CHECKED(String, name, 1);
4191
4192 // Check if the name is trivially convertible to an index and get the element
4193 // if so.
4194 uint32_t index;
4195 if (name->AsArrayIndex(&index)) {
4196 Handle<FixedArray> details = Factory::NewFixedArray(2);
4197 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4198 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4199 return *Factory::NewJSArrayWithElements(details);
4200 }
4201
4202 // Perform standard local lookup on the object.
4203 LookupResult result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004204 obj->Lookup(*name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 if (result.IsProperty()) {
4206 Handle<Object> value(DebugLookupResultValue(&result));
4207 Handle<FixedArray> details = Factory::NewFixedArray(2);
4208 details->set(0, *value);
4209 details->set(1, result.GetPropertyDetails().AsSmi());
4210 return *Factory::NewJSArrayWithElements(details);
4211 }
4212 return Heap::undefined_value();
4213}
4214
4215
4216static Object* Runtime_DebugGetProperty(Arguments args) {
4217 HandleScope scope;
4218
4219 ASSERT(args.length() == 2);
4220
4221 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4222 CONVERT_ARG_CHECKED(String, name, 1);
4223
4224 LookupResult result;
4225 obj->Lookup(*name, &result);
4226 if (result.IsProperty()) {
4227 return DebugLookupResultValue(&result);
4228 }
4229 return Heap::undefined_value();
4230}
4231
4232
4233// Return the names of the local named properties.
4234// args[0]: object
4235static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4236 HandleScope scope;
4237 ASSERT(args.length() == 1);
4238 if (!args[0]->IsJSObject()) {
4239 return Heap::undefined_value();
4240 }
4241 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4242
4243 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4244 Handle<FixedArray> names = Factory::NewFixedArray(n);
4245 obj->GetLocalPropertyNames(*names);
4246 return *Factory::NewJSArrayWithElements(names);
4247}
4248
4249
4250// Return the names of the local indexed properties.
4251// args[0]: object
4252static Object* Runtime_DebugLocalElementNames(Arguments args) {
4253 HandleScope scope;
4254 ASSERT(args.length() == 1);
4255 if (!args[0]->IsJSObject()) {
4256 return Heap::undefined_value();
4257 }
4258 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4259
4260 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4261 Handle<FixedArray> names = Factory::NewFixedArray(n);
4262 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4263 return *Factory::NewJSArrayWithElements(names);
4264}
4265
4266
4267// Return the property type calculated from the property details.
4268// args[0]: smi with property details.
4269static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4270 ASSERT(args.length() == 1);
4271 CONVERT_CHECKED(Smi, details, args[0]);
4272 PropertyType type = PropertyDetails(details).type();
4273 return Smi::FromInt(static_cast<int>(type));
4274}
4275
4276
4277// Return the property attribute calculated from the property details.
4278// args[0]: smi with property details.
4279static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4280 ASSERT(args.length() == 1);
4281 CONVERT_CHECKED(Smi, details, args[0]);
4282 PropertyAttributes attributes = PropertyDetails(details).attributes();
4283 return Smi::FromInt(static_cast<int>(attributes));
4284}
4285
4286
4287// Return the property insertion index calculated from the property details.
4288// args[0]: smi with property details.
4289static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4290 ASSERT(args.length() == 1);
4291 CONVERT_CHECKED(Smi, details, args[0]);
4292 int index = PropertyDetails(details).index();
4293 return Smi::FromInt(index);
4294}
4295
4296
4297// Return information on whether an object has a named or indexed interceptor.
4298// args[0]: object
4299static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4300 HandleScope scope;
4301 ASSERT(args.length() == 1);
4302 if (!args[0]->IsJSObject()) {
4303 return Smi::FromInt(0);
4304 }
4305 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4306
4307 int result = 0;
4308 if (obj->HasNamedInterceptor()) result |= 2;
4309 if (obj->HasIndexedInterceptor()) result |= 1;
4310
4311 return Smi::FromInt(result);
4312}
4313
4314
4315// Return property names from named interceptor.
4316// args[0]: object
4317static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4318 HandleScope scope;
4319 ASSERT(args.length() == 1);
4320 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4321 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4322
4323 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4324 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4325 return Heap::undefined_value();
4326}
4327
4328
4329// Return element names from indexed interceptor.
4330// args[0]: object
4331static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4332 HandleScope scope;
4333 ASSERT(args.length() == 1);
4334 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4335 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4336
4337 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4338 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4339 return Heap::undefined_value();
4340}
4341
4342
4343// Return property value from named interceptor.
4344// args[0]: object
4345// args[1]: property name
4346static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4347 HandleScope scope;
4348 ASSERT(args.length() == 2);
4349 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4350 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4351 CONVERT_ARG_CHECKED(String, name, 1);
4352
4353 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004354 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355}
4356
4357
4358// Return element value from indexed interceptor.
4359// args[0]: object
4360// args[1]: index
4361static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4362 HandleScope scope;
4363 ASSERT(args.length() == 2);
4364 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4365 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4366 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4367
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004368 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004369}
4370
4371
4372static Object* Runtime_CheckExecutionState(Arguments args) {
4373 ASSERT(args.length() >= 1);
4374 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
4375 // Check that the break id is valid and that there is a valid frame
4376 // where execution is broken.
4377 if (break_id != Top::break_id() ||
4378 Top::break_frame_id() == StackFrame::NO_ID) {
4379 return Top::Throw(Heap::illegal_execution_state_symbol());
4380 }
4381
4382 return Heap::true_value();
4383}
4384
4385
4386static Object* Runtime_GetFrameCount(Arguments args) {
4387 HandleScope scope;
4388 ASSERT(args.length() == 1);
4389
4390 // Check arguments.
4391 Object* result = Runtime_CheckExecutionState(args);
4392 if (result->IsFailure()) return result;
4393
4394 // Count all frames which are relevant to debugging stack trace.
4395 int n = 0;
4396 StackFrame::Id id = Top::break_frame_id();
4397 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4398 return Smi::FromInt(n);
4399}
4400
4401
4402static const int kFrameDetailsFrameIdIndex = 0;
4403static const int kFrameDetailsReceiverIndex = 1;
4404static const int kFrameDetailsFunctionIndex = 2;
4405static const int kFrameDetailsArgumentCountIndex = 3;
4406static const int kFrameDetailsLocalCountIndex = 4;
4407static const int kFrameDetailsSourcePositionIndex = 5;
4408static const int kFrameDetailsConstructCallIndex = 6;
4409static const int kFrameDetailsDebuggerFrameIndex = 7;
4410static const int kFrameDetailsFirstDynamicIndex = 8;
4411
4412// Return an array with frame details
4413// args[0]: number: break id
4414// args[1]: number: frame index
4415//
4416// The array returned contains the following information:
4417// 0: Frame id
4418// 1: Receiver
4419// 2: Function
4420// 3: Argument count
4421// 4: Local count
4422// 5: Source position
4423// 6: Constructor call
4424// 7: Debugger frame
4425// Arguments name, value
4426// Locals name, value
4427static Object* Runtime_GetFrameDetails(Arguments args) {
4428 HandleScope scope;
4429 ASSERT(args.length() == 2);
4430
4431 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004432 Object* check = Runtime_CheckExecutionState(args);
4433 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4435
4436 // Find the relevant frame with the requested index.
4437 StackFrame::Id id = Top::break_frame_id();
4438 int count = 0;
4439 JavaScriptFrameIterator it(id);
4440 for (; !it.done(); it.Advance()) {
4441 if (count == index) break;
4442 count++;
4443 }
4444 if (it.done()) return Heap::undefined_value();
4445
4446 // Traverse the saved contexts chain to find the active context for the
4447 // selected frame.
4448 SaveContext* save = Top::save_context();
4449 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
4450 save = save->prev();
4451 }
4452
4453 // Get the frame id.
4454 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
4455
4456 // Find source position.
4457 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
4458
4459 // Check for constructor frame.
4460 bool constructor = it.frame()->IsConstructor();
4461
4462 // Get code and read scope info from it for local variable information.
4463 Handle<Code> code(it.frame()->FindCode());
4464 ScopeInfo<> info(*code);
4465
4466 // Get the context.
4467 Handle<Context> context(Context::cast(it.frame()->context()));
4468
4469 // Get the locals names and values into a temporary array.
4470 //
4471 // TODO(1240907): Hide compiler-introduced stack variables
4472 // (e.g. .result)? For users of the debugger, they will probably be
4473 // confusing.
4474 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
4475 for (int i = 0; i < info.NumberOfLocals(); i++) {
4476 // Name of the local.
4477 locals->set(i * 2, *info.LocalName(i));
4478
4479 // Fetch the value of the local - either from the stack or from a
4480 // heap-allocated context.
4481 if (i < info.number_of_stack_slots()) {
4482 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
4483 } else {
4484 Handle<String> name = info.LocalName(i);
4485 // Traverse the context chain to the function context as all local
4486 // variables stored in the context will be on the function context.
4487 while (context->previous() != NULL) {
4488 context = Handle<Context>(context->previous());
4489 }
4490 ASSERT(context->is_function_context());
4491 locals->set(i * 2 + 1,
4492 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
4493 NULL)));
4494 }
4495 }
4496
4497 // Now advance to the arguments adapter frame (if any). If contains all
4498 // the provided parameters and
4499
4500 // Now advance to the arguments adapter frame (if any). It contains all
4501 // the provided parameters whereas the function frame always have the number
4502 // of arguments matching the functions parameters. The rest of the
4503 // information (except for what is collected above) is the same.
4504 it.AdvanceToArgumentsFrame();
4505
4506 // Find the number of arguments to fill. At least fill the number of
4507 // parameters for the function and fill more if more parameters are provided.
4508 int argument_count = info.number_of_parameters();
4509 if (argument_count < it.frame()->GetProvidedParametersCount()) {
4510 argument_count = it.frame()->GetProvidedParametersCount();
4511 }
4512
4513 // Calculate the size of the result.
4514 int details_size = kFrameDetailsFirstDynamicIndex +
4515 2 * (argument_count + info.NumberOfLocals());
4516 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
4517
4518 // Add the frame id.
4519 details->set(kFrameDetailsFrameIdIndex, *frame_id);
4520
4521 // Add the function (same as in function frame).
4522 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
4523
4524 // Add the arguments count.
4525 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
4526
4527 // Add the locals count
4528 details->set(kFrameDetailsLocalCountIndex,
4529 Smi::FromInt(info.NumberOfLocals()));
4530
4531 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00004532 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
4534 } else {
4535 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
4536 }
4537
4538 // Add the constructor information.
4539 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
4540
4541 // Add information on whether this frame is invoked in the debugger context.
4542 details->set(kFrameDetailsDebuggerFrameIndex,
4543 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
4544
4545 // Fill the dynamic part.
4546 int details_index = kFrameDetailsFirstDynamicIndex;
4547
4548 // Add arguments name and value.
4549 for (int i = 0; i < argument_count; i++) {
4550 // Name of the argument.
4551 if (i < info.number_of_parameters()) {
4552 details->set(details_index++, *info.parameter_name(i));
4553 } else {
4554 details->set(details_index++, Heap::undefined_value());
4555 }
4556
4557 // Parameter value.
4558 if (i < it.frame()->GetProvidedParametersCount()) {
4559 details->set(details_index++, it.frame()->GetParameter(i));
4560 } else {
4561 details->set(details_index++, Heap::undefined_value());
4562 }
4563 }
4564
4565 // Add locals name and value from the temporary copy from the function frame.
4566 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
4567 details->set(details_index++, locals->get(i));
4568 }
4569
4570 // Add the receiver (same as in function frame).
4571 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
4572 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
4573 Handle<Object> receiver(it.frame()->receiver());
4574 if (!receiver->IsJSObject()) {
4575 // If the receiver is NOT a JSObject we have hit an optimization
4576 // where a value object is not converted into a wrapped JS objects.
4577 // To hide this optimization from the debugger, we wrap the receiver
4578 // by creating correct wrapper object based on the calling frame's
4579 // global context.
4580 it.Advance();
4581 Handle<Context> calling_frames_global_context(
4582 Context::cast(Context::cast(it.frame()->context())->global_context()));
4583 receiver = Factory::ToObject(receiver, calling_frames_global_context);
4584 }
4585 details->set(kFrameDetailsReceiverIndex, *receiver);
4586
4587 ASSERT_EQ(details_size, details_index);
4588 return *Factory::NewJSArrayWithElements(details);
4589}
4590
4591
4592static Object* Runtime_GetCFrames(Arguments args) {
4593 HandleScope scope;
4594 ASSERT(args.length() == 1);
4595 Object* result = Runtime_CheckExecutionState(args);
4596 if (result->IsFailure()) return result;
4597
4598 static const int kMaxCFramesSize = 200;
4599 OS::StackFrame frames[kMaxCFramesSize];
4600 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4601 if (frames_count == OS::kStackWalkError) {
4602 return Heap::undefined_value();
4603 }
4604
4605 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4606 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4607 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4608 for (int i = 0; i < frames_count; i++) {
4609 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4610 frame_value->SetProperty(
4611 *address_str,
4612 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4613 NONE);
4614
4615 // Get the stack walk text for this frame.
4616 Handle<String> frame_text;
4617 if (strlen(frames[i].text) > 0) {
4618 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4619 frame_text = Factory::NewStringFromAscii(str);
4620 }
4621
4622 if (!frame_text.is_null()) {
4623 frame_value->SetProperty(*text_str, *frame_text, NONE);
4624 }
4625
4626 frames_array->set(i, *frame_value);
4627 }
4628 return *Factory::NewJSArrayWithElements(frames_array);
4629}
4630
4631
4632static Object* Runtime_GetBreakLocations(Arguments args) {
4633 HandleScope scope;
4634 ASSERT(args.length() == 1);
4635
4636 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4637 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4638 // Find the number of break points
4639 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4640 if (break_locations->IsUndefined()) return Heap::undefined_value();
4641 // Return array as JS array
4642 return *Factory::NewJSArrayWithElements(
4643 Handle<FixedArray>::cast(break_locations));
4644}
4645
4646
4647// Set a break point in a function
4648// args[0]: function
4649// args[1]: number: break source position (within the function source)
4650// args[2]: number: break point object
4651static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4652 HandleScope scope;
4653 ASSERT(args.length() == 3);
4654 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4655 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4656 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4657 RUNTIME_ASSERT(source_position >= 0);
4658 Handle<Object> break_point_object_arg = args.at<Object>(2);
4659
4660 // Set break point.
4661 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4662
4663 return Heap::undefined_value();
4664}
4665
4666
4667static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4668 int position) {
4669 // Iterate the heap looking for SharedFunctionInfo generated from the
4670 // script. The inner most SharedFunctionInfo containing the source position
4671 // for the requested break point is found.
4672 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4673 // which is found is not compiled it is compiled and the heap is iterated
4674 // again as the compilation might create inner functions from the newly
4675 // compiled function and the actual requested break point might be in one of
4676 // these functions.
4677 bool done = false;
4678 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00004679 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 Handle<SharedFunctionInfo> target;
4681 // The current candidate for the last function in script:
4682 Handle<SharedFunctionInfo> last;
4683 while (!done) {
4684 HeapIterator iterator;
4685 while (iterator.has_next()) {
4686 HeapObject* obj = iterator.next();
4687 ASSERT(obj != NULL);
4688 if (obj->IsSharedFunctionInfo()) {
4689 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4690 if (shared->script() == *script) {
4691 // If the SharedFunctionInfo found has the requested script data and
4692 // contains the source position it is a candidate.
4693 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00004694 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 start_position = shared->start_position();
4696 }
4697 if (start_position <= position &&
4698 position <= shared->end_position()) {
4699 // If there is no candidate or this function is within the currrent
4700 // candidate this is the new candidate.
4701 if (target.is_null()) {
4702 target_start_position = start_position;
4703 target = shared;
4704 } else {
4705 if (target_start_position < start_position &&
4706 shared->end_position() < target->end_position()) {
4707 target_start_position = start_position;
4708 target = shared;
4709 }
4710 }
4711 }
4712
4713 // Keep track of the last function in the script.
4714 if (last.is_null() ||
4715 shared->end_position() > last->start_position()) {
4716 last = shared;
4717 }
4718 }
4719 }
4720 }
4721
4722 // Make sure some candidate is selected.
4723 if (target.is_null()) {
4724 if (!last.is_null()) {
4725 // Position after the last function - use last.
4726 target = last;
4727 } else {
4728 // Unable to find function - possibly script without any function.
4729 return Heap::undefined_value();
4730 }
4731 }
4732
4733 // If the candidate found is compiled we are done. NOTE: when lazy
4734 // compilation of inner functions is introduced some additional checking
4735 // needs to be done here to compile inner functions.
4736 done = target->is_compiled();
4737 if (!done) {
4738 // If the candidate is not compiled compile it to reveal any inner
4739 // functions which might contain the requested source position.
4740 CompileLazyShared(target, KEEP_EXCEPTION);
4741 }
4742 }
4743
4744 return *target;
4745}
4746
4747
4748// Change the state of a break point in a script. NOTE: Regarding performance
4749// see the NOTE for GetScriptFromScriptData.
4750// args[0]: script to set break point in
4751// args[1]: number: break source position (within the script source)
4752// args[2]: number: break point object
4753static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4754 HandleScope scope;
4755 ASSERT(args.length() == 3);
4756 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4757 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4758 RUNTIME_ASSERT(source_position >= 0);
4759 Handle<Object> break_point_object_arg = args.at<Object>(2);
4760
4761 // Get the script from the script wrapper.
4762 RUNTIME_ASSERT(wrapper->value()->IsScript());
4763 Handle<Script> script(Script::cast(wrapper->value()));
4764
4765 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4766 if (!result->IsUndefined()) {
4767 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4768 // Find position within function. The script position might be before the
4769 // source position of the first function.
4770 int position;
4771 if (shared->start_position() > source_position) {
4772 position = 0;
4773 } else {
4774 position = source_position - shared->start_position();
4775 }
4776 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4777 }
4778 return Heap::undefined_value();
4779}
4780
4781
4782// Clear a break point
4783// args[0]: number: break point object
4784static Object* Runtime_ClearBreakPoint(Arguments args) {
4785 HandleScope scope;
4786 ASSERT(args.length() == 1);
4787 Handle<Object> break_point_object_arg = args.at<Object>(0);
4788
4789 // Clear break point.
4790 Debug::ClearBreakPoint(break_point_object_arg);
4791
4792 return Heap::undefined_value();
4793}
4794
4795
4796// Change the state of break on exceptions
4797// args[0]: boolean indicating uncaught exceptions
4798// args[1]: boolean indicating on/off
4799static Object* Runtime_ChangeBreakOnException(Arguments args) {
4800 HandleScope scope;
4801 ASSERT(args.length() == 2);
4802 ASSERT(args[0]->IsNumber());
4803 ASSERT(args[1]->IsBoolean());
4804
4805 // Update break point state
4806 ExceptionBreakType type =
4807 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4808 bool enable = args[1]->ToBoolean()->IsTrue();
4809 Debug::ChangeBreakOnException(type, enable);
4810 return Heap::undefined_value();
4811}
4812
4813
4814// Prepare for stepping
4815// args[0]: break id for checking execution state
4816// args[1]: step action from the enumeration StepAction
4817// args[2]: number of times to perform the step
4818static Object* Runtime_PrepareStep(Arguments args) {
4819 HandleScope scope;
4820 ASSERT(args.length() == 3);
4821 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004822 Object* check = Runtime_CheckExecutionState(args);
4823 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4825 return Top::Throw(Heap::illegal_argument_symbol());
4826 }
4827
4828 // Get the step action and check validity.
4829 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4830 if (step_action != StepIn &&
4831 step_action != StepNext &&
4832 step_action != StepOut &&
4833 step_action != StepInMin &&
4834 step_action != StepMin) {
4835 return Top::Throw(Heap::illegal_argument_symbol());
4836 }
4837
4838 // Get the number of steps.
4839 int step_count = NumberToInt32(args[2]);
4840 if (step_count < 1) {
4841 return Top::Throw(Heap::illegal_argument_symbol());
4842 }
4843
4844 // Prepare step.
4845 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4846 return Heap::undefined_value();
4847}
4848
4849
4850// Clear all stepping set by PrepareStep.
4851static Object* Runtime_ClearStepping(Arguments args) {
4852 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004853 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 Debug::ClearStepping();
4855 return Heap::undefined_value();
4856}
4857
4858
4859// Creates a copy of the with context chain. The copy of the context chain is
4860// is linked to the function context supplied.
4861static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4862 Handle<Context> function_context) {
4863 // At the bottom of the chain. Return the function context to link to.
4864 if (context_chain->is_function_context()) {
4865 return function_context;
4866 }
4867
4868 // Recursively copy the with contexts.
4869 Handle<Context> previous(context_chain->previous());
4870 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4871 return Factory::NewWithContext(
4872 CopyWithContextChain(function_context, previous), extension);
4873}
4874
4875
4876// Helper function to find or create the arguments object for
4877// Runtime_DebugEvaluate.
4878static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4879 Handle<JSFunction> function,
4880 Handle<Code> code,
4881 const ScopeInfo<>* sinfo,
4882 Handle<Context> function_context) {
4883 // Try to find the value of 'arguments' to pass as parameter. If it is not
4884 // found (that is the debugged function does not reference 'arguments' and
4885 // does not support eval) then create an 'arguments' object.
4886 int index;
4887 if (sinfo->number_of_stack_slots() > 0) {
4888 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4889 if (index != -1) {
4890 return Handle<Object>(frame->GetExpression(index));
4891 }
4892 }
4893
4894 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4895 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4896 NULL);
4897 if (index != -1) {
4898 return Handle<Object>(function_context->get(index));
4899 }
4900 }
4901
4902 const int length = frame->GetProvidedParametersCount();
4903 Handle<Object> arguments = Factory::NewArgumentsObject(function, length);
4904 FixedArray* array = FixedArray::cast(JSObject::cast(*arguments)->elements());
4905 ASSERT(array->length() == length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004906 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004907 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004908 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004909 }
4910 return arguments;
4911}
4912
4913
4914// Evaluate a piece of JavaScript in the context of a stack frame for
4915// debugging. This is acomplished by creating a new context which in its
4916// extension part has all the parameters and locals of the function on the
4917// stack frame. A function which calls eval with the code to evaluate is then
4918// compiled in this context and called in this context. As this context
4919// replaces the context of the function on the stack frame a new (empty)
4920// function is created as well to be used as the closure for the context.
4921// This function and the context acts as replacements for the function on the
4922// stack frame presenting the same view of the values of parameters and
4923// local variables as if the piece of JavaScript was evaluated at the point
4924// where the function on the stack frame is currently stopped.
4925static Object* Runtime_DebugEvaluate(Arguments args) {
4926 HandleScope scope;
4927
4928 // Check the execution state and decode arguments frame and source to be
4929 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004930 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931 Object* check_result = Runtime_CheckExecutionState(args);
4932 if (check_result->IsFailure()) return check_result;
4933 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4934 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004935 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4936
4937 // Handle the processing of break.
4938 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939
4940 // Get the frame where the debugging is performed.
4941 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4942 JavaScriptFrameIterator it(id);
4943 JavaScriptFrame* frame = it.frame();
4944 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4945 Handle<Code> code(function->code());
4946 ScopeInfo<> sinfo(*code);
4947
4948 // Traverse the saved contexts chain to find the active context for the
4949 // selected frame.
4950 SaveContext* save = Top::save_context();
4951 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4952 save = save->prev();
4953 }
4954 ASSERT(save != NULL);
4955 SaveContext savex;
4956 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004957
4958 // Create the (empty) function replacing the function on the stack frame for
4959 // the purpose of evaluating in the context created below. It is important
4960 // that this function does not describe any parameters and local variables
4961 // in the context. If it does then this will cause problems with the lookup
4962 // in Context::Lookup, where context slots for parameters and local variables
4963 // are looked at before the extension object.
4964 Handle<JSFunction> go_between =
4965 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4966 go_between->set_context(function->context());
4967#ifdef DEBUG
4968 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4969 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4970 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4971#endif
4972
4973 // Allocate and initialize a context extension object with all the
4974 // arguments, stack locals heap locals and extension properties of the
4975 // debugged function.
4976 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4977 // First fill all parameters to the context extension.
4978 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4979 SetProperty(context_ext,
4980 sinfo.parameter_name(i),
4981 Handle<Object>(frame->GetParameter(i)), NONE);
4982 }
4983 // Second fill all stack locals to the context extension.
4984 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4985 SetProperty(context_ext,
4986 sinfo.stack_slot_name(i),
4987 Handle<Object>(frame->GetExpression(i)), NONE);
4988 }
4989 // Third fill all context locals to the context extension.
4990 Handle<Context> frame_context(Context::cast(frame->context()));
4991 Handle<Context> function_context(frame_context->fcontext());
4992 for (int i = Context::MIN_CONTEXT_SLOTS;
4993 i < sinfo.number_of_context_slots();
4994 ++i) {
4995 int context_index =
4996 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
4997 SetProperty(context_ext,
4998 sinfo.context_slot_name(i),
4999 Handle<Object>(function_context->get(context_index)), NONE);
5000 }
5001 // Finally copy any properties from the function context extension. This will
5002 // be variables introduced by eval.
5003 if (function_context->extension() != NULL &&
5004 !function_context->IsGlobalContext()) {
5005 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5006 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5007 for (int i = 0; i < keys->length(); i++) {
5008 // Names of variables introduced by eval are strings.
5009 ASSERT(keys->get(i)->IsString());
5010 Handle<String> key(String::cast(keys->get(i)));
5011 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5012 }
5013 }
5014
5015 // Allocate a new context for the debug evaluation and set the extension
5016 // object build.
5017 Handle<Context> context =
5018 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5019 context->set_extension(*context_ext);
5020 // Copy any with contexts present and chain them in front of this context.
5021 context = CopyWithContextChain(frame_context, context);
5022
5023 // Wrap the evaluation statement in a new function compiled in the newly
5024 // created context. The function has one parameter which has to be called
5025 // 'arguments'. This it to have access to what would have been 'arguments' in
5026 // the function beeing debugged.
5027 // function(arguments,__source__) {return eval(__source__);}
5028 static const char* source_str =
5029 "function(arguments,__source__){return eval(__source__);}";
5030 static const int source_str_length = strlen(source_str);
5031 Handle<String> function_source =
5032 Factory::NewStringFromAscii(Vector<const char>(source_str,
5033 source_str_length));
5034 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00005035 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005036 if (boilerplate.is_null()) return Failure::Exception();
5037 Handle<JSFunction> compiled_function =
5038 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5039
5040 // Invoke the result of the compilation to get the evaluation function.
5041 bool has_pending_exception;
5042 Handle<Object> receiver(frame->receiver());
5043 Handle<Object> evaluation_function =
5044 Execution::Call(compiled_function, receiver, 0, NULL,
5045 &has_pending_exception);
5046
5047 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5048 function_context);
5049
5050 // Invoke the evaluation function and return the result.
5051 const int argc = 2;
5052 Object** argv[argc] = { arguments.location(),
5053 Handle<Object>::cast(source).location() };
5054 Handle<Object> result =
5055 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5056 argc, argv, &has_pending_exception);
5057 return *result;
5058}
5059
5060
5061static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5062 HandleScope scope;
5063
5064 // Check the execution state and decode arguments frame and source to be
5065 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005066 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067 Object* check_result = Runtime_CheckExecutionState(args);
5068 if (check_result->IsFailure()) return check_result;
5069 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005070 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5071
5072 // Handle the processing of break.
5073 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005074
5075 // Enter the top context from before the debugger was invoked.
5076 SaveContext save;
5077 SaveContext* top = &save;
5078 while (top != NULL && *top->context() == *Debug::debug_context()) {
5079 top = top->prev();
5080 }
5081 if (top != NULL) {
5082 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083 }
5084
5085 // Get the global context now set to the top context from before the
5086 // debugger was invoked.
5087 Handle<Context> context = Top::global_context();
5088
5089 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00005090 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091 if (boilerplate.is_null()) return Failure::Exception();
5092 Handle<JSFunction> compiled_function =
5093 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5094 context));
5095
5096 // Invoke the result of the compilation to get the evaluation function.
5097 bool has_pending_exception;
5098 Handle<Object> receiver = Top::global();
5099 Handle<Object> result =
5100 Execution::Call(compiled_function, receiver, 0, NULL,
5101 &has_pending_exception);
5102 return *result;
5103}
5104
5105
5106// Helper function used by Runtime_DebugGetLoadedScripts below.
5107static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5108 NoHandleAllocation ha;
5109 AssertNoAllocation no_alloc;
5110
5111 // Get hold of the current empty script.
5112 Context* context = Top::context()->global_context();
5113 Script* empty = context->empty_script();
5114
5115 // Scan heap for Script objects.
5116 int count = 0;
5117 HeapIterator iterator;
5118 while (iterator.has_next()) {
5119 HeapObject* obj = iterator.next();
5120 ASSERT(obj != NULL);
5121 if (obj->IsScript() && obj != empty) {
5122 if (instances != NULL && count < instances_size) {
5123 instances->set(count, obj);
5124 }
5125 count++;
5126 }
5127 }
5128
5129 return count;
5130}
5131
5132
5133static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5134 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005135 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136
5137 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
5138 // rid of all the cached script wrappes and the second gets rid of the
5139 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005140 Heap::CollectAllGarbage();
5141 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142
5143 // Get the number of scripts.
5144 int count;
5145 count = DebugGetLoadedScripts(NULL, 0);
5146
5147 // Allocate an array to hold the result.
5148 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5149
5150 // Fill the script objects.
5151 count = DebugGetLoadedScripts(*instances, count);
5152
5153 // Convert the script objects to proper JS objects.
5154 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005155 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5156 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5157 // because using
5158 // instances->set(i, *GetScriptWrapper(script))
5159 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5160 // already have deferenced the instances handle.
5161 Handle<JSValue> wrapper = GetScriptWrapper(script);
5162 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163 }
5164
5165 // Return result as a JS array.
5166 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5167 Handle<JSArray>::cast(result)->SetContent(*instances);
5168 return *result;
5169}
5170
5171
5172// Helper function used by Runtime_DebugReferencedBy below.
5173static int DebugReferencedBy(JSObject* target,
5174 Object* instance_filter, int max_references,
5175 FixedArray* instances, int instances_size,
5176 JSFunction* context_extension_function,
5177 JSFunction* arguments_function) {
5178 NoHandleAllocation ha;
5179 AssertNoAllocation no_alloc;
5180
5181 // Iterate the heap.
5182 int count = 0;
5183 JSObject* last = NULL;
5184 HeapIterator iterator;
5185 while (iterator.has_next() &&
5186 (max_references == 0 || count < max_references)) {
5187 // Only look at all JSObjects.
5188 HeapObject* heap_obj = iterator.next();
5189 if (heap_obj->IsJSObject()) {
5190 // Skip context extension objects and argument arrays as these are
5191 // checked in the context of functions using them.
5192 JSObject* obj = JSObject::cast(heap_obj);
5193 if (obj->map()->constructor() == context_extension_function ||
5194 obj->map()->constructor() == arguments_function) {
5195 continue;
5196 }
5197
5198 // Check if the JS object has a reference to the object looked for.
5199 if (obj->ReferencesObject(target)) {
5200 // Check instance filter if supplied. This is normally used to avoid
5201 // references from mirror objects (see Runtime_IsInPrototypeChain).
5202 if (!instance_filter->IsUndefined()) {
5203 Object* V = obj;
5204 while (true) {
5205 Object* prototype = V->GetPrototype();
5206 if (prototype->IsNull()) {
5207 break;
5208 }
5209 if (instance_filter == prototype) {
5210 obj = NULL; // Don't add this object.
5211 break;
5212 }
5213 V = prototype;
5214 }
5215 }
5216
5217 if (obj != NULL) {
5218 // Valid reference found add to instance array if supplied an update
5219 // count.
5220 if (instances != NULL && count < instances_size) {
5221 instances->set(count, obj);
5222 }
5223 last = obj;
5224 count++;
5225 }
5226 }
5227 }
5228 }
5229
5230 // Check for circular reference only. This can happen when the object is only
5231 // referenced from mirrors and has a circular reference in which case the
5232 // object is not really alive and would have been garbage collected if not
5233 // referenced from the mirror.
5234 if (count == 1 && last == target) {
5235 count = 0;
5236 }
5237
5238 // Return the number of referencing objects found.
5239 return count;
5240}
5241
5242
5243// Scan the heap for objects with direct references to an object
5244// args[0]: the object to find references to
5245// args[1]: constructor function for instances to exclude (Mirror)
5246// args[2]: the the maximum number of objects to return
5247static Object* Runtime_DebugReferencedBy(Arguments args) {
5248 ASSERT(args.length() == 3);
5249
5250 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005251 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252
5253 // Check parameters.
5254 CONVERT_CHECKED(JSObject, target, args[0]);
5255 Object* instance_filter = args[1];
5256 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5257 instance_filter->IsJSObject());
5258 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5259 RUNTIME_ASSERT(max_references >= 0);
5260
5261 // Get the constructor function for context extension and arguments array.
5262 JSFunction* context_extension_function =
5263 Top::context()->global_context()->context_extension_function();
5264 JSObject* arguments_boilerplate =
5265 Top::context()->global_context()->arguments_boilerplate();
5266 JSFunction* arguments_function =
5267 JSFunction::cast(arguments_boilerplate->map()->constructor());
5268
5269 // Get the number of referencing objects.
5270 int count;
5271 count = DebugReferencedBy(target, instance_filter, max_references,
5272 NULL, 0,
5273 context_extension_function, arguments_function);
5274
5275 // Allocate an array to hold the result.
5276 Object* object = Heap::AllocateFixedArray(count);
5277 if (object->IsFailure()) return object;
5278 FixedArray* instances = FixedArray::cast(object);
5279
5280 // Fill the referencing objects.
5281 count = DebugReferencedBy(target, instance_filter, max_references,
5282 instances, count,
5283 context_extension_function, arguments_function);
5284
5285 // Return result as JS array.
5286 Object* result =
5287 Heap::AllocateJSObject(
5288 Top::context()->global_context()->array_function());
5289 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5290 return result;
5291}
5292
5293
5294// Helper function used by Runtime_DebugConstructedBy below.
5295static int DebugConstructedBy(JSFunction* constructor, int max_references,
5296 FixedArray* instances, int instances_size) {
5297 AssertNoAllocation no_alloc;
5298
5299 // Iterate the heap.
5300 int count = 0;
5301 HeapIterator iterator;
5302 while (iterator.has_next() &&
5303 (max_references == 0 || count < max_references)) {
5304 // Only look at all JSObjects.
5305 HeapObject* heap_obj = iterator.next();
5306 if (heap_obj->IsJSObject()) {
5307 JSObject* obj = JSObject::cast(heap_obj);
5308 if (obj->map()->constructor() == constructor) {
5309 // Valid reference found add to instance array if supplied an update
5310 // count.
5311 if (instances != NULL && count < instances_size) {
5312 instances->set(count, obj);
5313 }
5314 count++;
5315 }
5316 }
5317 }
5318
5319 // Return the number of referencing objects found.
5320 return count;
5321}
5322
5323
5324// Scan the heap for objects constructed by a specific function.
5325// args[0]: the constructor to find instances of
5326// args[1]: the the maximum number of objects to return
5327static Object* Runtime_DebugConstructedBy(Arguments args) {
5328 ASSERT(args.length() == 2);
5329
5330 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005331 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005332
5333 // Check parameters.
5334 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5335 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5336 RUNTIME_ASSERT(max_references >= 0);
5337
5338 // Get the number of referencing objects.
5339 int count;
5340 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5341
5342 // Allocate an array to hold the result.
5343 Object* object = Heap::AllocateFixedArray(count);
5344 if (object->IsFailure()) return object;
5345 FixedArray* instances = FixedArray::cast(object);
5346
5347 // Fill the referencing objects.
5348 count = DebugConstructedBy(constructor, max_references, instances, count);
5349
5350 // Return result as JS array.
5351 Object* result =
5352 Heap::AllocateJSObject(
5353 Top::context()->global_context()->array_function());
5354 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5355 return result;
5356}
5357
5358
5359static Object* Runtime_GetPrototype(Arguments args) {
5360 ASSERT(args.length() == 1);
5361
5362 CONVERT_CHECKED(JSObject, obj, args[0]);
5363
5364 return obj->GetPrototype();
5365}
5366
5367
5368static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005369 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 CPU::DebugBreak();
5371 return Heap::undefined_value();
5372}
5373
5374
5375// Finds the script object from the script data. NOTE: This operation uses
5376// heap traversal to find the function generated for the source position
5377// for the requested break point. For lazily compiled functions several heap
5378// traversals might be required rendering this operation as a rather slow
5379// operation. However for setting break points which is normally done through
5380// some kind of user interaction the performance is not crucial.
5381static Handle<Object> Runtime_GetScriptFromScriptName(
5382 Handle<String> script_name) {
5383 // Scan the heap for Script objects to find the script with the requested
5384 // script data.
5385 Handle<Script> script;
5386 HeapIterator iterator;
5387 while (script.is_null() && iterator.has_next()) {
5388 HeapObject* obj = iterator.next();
5389 // If a script is found check if it has the script data requested.
5390 if (obj->IsScript()) {
5391 if (Script::cast(obj)->name()->IsString()) {
5392 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5393 script = Handle<Script>(Script::cast(obj));
5394 }
5395 }
5396 }
5397 }
5398
5399 // If no script with the requested script data is found return undefined.
5400 if (script.is_null()) return Factory::undefined_value();
5401
5402 // Return the script found.
5403 return GetScriptWrapper(script);
5404}
5405
5406
5407// Get the script object from script data. NOTE: Regarding performance
5408// see the NOTE for GetScriptFromScriptData.
5409// args[0]: script data for the script to find the source for
5410static Object* Runtime_GetScript(Arguments args) {
5411 HandleScope scope;
5412
5413 ASSERT(args.length() == 1);
5414
5415 CONVERT_CHECKED(String, script_name, args[0]);
5416
5417 // Find the requested script.
5418 Handle<Object> result =
5419 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5420 return *result;
5421}
5422
5423
5424static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5425#ifdef DEBUG
5426 HandleScope scope;
5427 ASSERT(args.length() == 1);
5428 // Get the function and make sure it is compiled.
5429 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5430 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5431 return Failure::Exception();
5432 }
5433 func->code()->PrintLn();
5434#endif // DEBUG
5435 return Heap::undefined_value();
5436}
5437
5438
5439static Object* Runtime_Abort(Arguments args) {
5440 ASSERT(args.length() == 2);
5441 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
5442 Smi::cast(args[1])->value());
5443 Top::PrintStack();
5444 OS::Abort();
5445 UNREACHABLE();
5446 return NULL;
5447}
5448
5449
kasper.lund44510672008-07-25 07:37:58 +00005450#ifdef DEBUG
5451// ListNatives is ONLY used by the fuzz-natives.js in debug mode
5452// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005454 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455 HandleScope scope;
5456 Handle<JSArray> result = Factory::NewJSArray(0);
5457 int index = 0;
5458#define ADD_ENTRY(Name, argc) \
5459 { \
5460 HandleScope inner; \
5461 Handle<String> name = \
5462 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
5463 Handle<JSArray> pair = Factory::NewJSArray(0); \
5464 SetElement(pair, 0, name); \
5465 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
5466 SetElement(result, index++, pair); \
5467 }
5468 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
5469#undef ADD_ENTRY
5470 return *result;
5471}
kasper.lund44510672008-07-25 07:37:58 +00005472#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473
5474
5475static Object* Runtime_IS_VAR(Arguments args) {
5476 UNREACHABLE(); // implemented as macro in the parser
5477 return NULL;
5478}
5479
5480
5481// ----------------------------------------------------------------------------
5482// Implementation of Runtime
5483
5484#define F(name, nargs) \
5485 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
5486 static_cast<int>(Runtime::k##name) },
5487
5488static Runtime::Function Runtime_functions[] = {
5489 RUNTIME_FUNCTION_LIST(F)
5490 { NULL, NULL, NULL, 0, -1 }
5491};
5492
5493#undef F
5494
5495
5496Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
5497 ASSERT(0 <= fid && fid < kNofFunctions);
5498 return &Runtime_functions[fid];
5499}
5500
5501
5502Runtime::Function* Runtime::FunctionForName(const char* name) {
5503 for (Function* f = Runtime_functions; f->name != NULL; f++) {
5504 if (strcmp(f->name, name) == 0) {
5505 return f;
5506 }
5507 }
5508 return NULL;
5509}
5510
5511
5512void Runtime::PerformGC(Object* result) {
5513 Failure* failure = Failure::cast(result);
5514 // Try to do a garbage collection; ignore it if it fails. The C
5515 // entry stub will throw an out-of-memory exception in that case.
5516 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5517}
5518
5519
5520} } // namespace v8::internal