blob: 9b79145a414a1c9abbb39edde5d311e9f8e10e9e [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"
45
46namespace v8 { namespace internal {
47
48
49#define RUNTIME_ASSERT(value) do { \
50 if (!(value)) return IllegalOperation(); \
51} while (false)
52
53// Cast the given object to a value of the specified type and store
54// it in a variable with the given name. If the object is not of the
55// expected type call IllegalOperation and return.
56#define CONVERT_CHECKED(Type, name, obj) \
57 RUNTIME_ASSERT(obj->Is##Type()); \
58 Type* name = Type::cast(obj);
59
60#define CONVERT_ARG_CHECKED(Type, name, index) \
61 RUNTIME_ASSERT(args[index]->Is##Type()); \
62 Handle<Type> name = args.at<Type>(index);
63
kasper.lundbd3ec4e2008-07-09 11:06:54 +000064// Cast the given object to a boolean and store it in a variable with
65// the given name. If the object is not a boolean call IllegalOperation
66// and return.
67#define CONVERT_BOOLEAN_CHECKED(name, obj) \
68 RUNTIME_ASSERT(obj->IsBoolean()); \
69 bool name = (obj)->IsTrue();
70
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071// Cast the given object to a double and store it in a variable with
72// the given name. If the object is not a number (as opposed to
73// the number not-a-number) call IllegalOperation and return.
74#define CONVERT_DOUBLE_CHECKED(name, obj) \
75 RUNTIME_ASSERT(obj->IsNumber()); \
76 double name = (obj)->Number();
77
78// Call the specified converter on the object *comand store the result in
79// a variable of the specified type with the given name. If the
80// object is not a Number call IllegalOperation and return.
81#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
82 RUNTIME_ASSERT(obj->IsNumber()); \
83 type name = NumberTo##Type(obj);
84
85// Non-reentrant string buffer for efficient general use in this file.
86static StaticResource<StringInputBuffer> string_input_buffer;
87
88
89static Object* IllegalOperation() {
90 return Top::Throw(Heap::illegal_access_symbol());
91}
92
93
94static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
95 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 return boilerplate->Copy();
97}
98
99
ager@chromium.org236ad962008-09-25 09:45:57 +0000100static Handle<Map> ComputeObjectLiteralMap(
101 Handle<Context> context,
102 Handle<FixedArray> constant_properties,
103 bool &is_result_from_cache) {
104 if (FLAG_canonicalize_object_literal_maps) {
105 // First find prefix of consecutive symbol keys.
106 int number_of_properties = constant_properties->length()/2;
107 int number_of_symbol_keys = 0;
108 while ((number_of_symbol_keys < number_of_properties) &&
109 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
110 number_of_symbol_keys++;
111 }
112 // Based on the number of prefix symbols key we decide whether
113 // to use the map cache in the global context.
114 const int kMaxKeys = 10;
115 if ((number_of_symbol_keys == number_of_properties)
116 && (number_of_symbol_keys < kMaxKeys)) {
117 // Create the fixed array with the key.
118 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
119 for (int i = 0; i < number_of_symbol_keys; i++) {
120 keys->set(i, constant_properties->get(i*2));
121 }
122 is_result_from_cache = true;
123 return Factory::ObjectLiteralMapFromCache(context, keys);
124 }
125 }
126 is_result_from_cache = false;
127 return Handle<Map>(context->object_function()->initial_map());
128}
129
130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
132 HandleScope scope;
133 ASSERT(args.length() == 3);
134 // Copy the arguments.
135 Handle<FixedArray> literals = args.at<FixedArray>(0);
136 int literals_index = Smi::cast(args[1])->value();
137 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000138 Handle<Context> context =
139 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
140
141 bool is_result_from_cache;
142 Handle<Map> map = ComputeObjectLiteralMap(context,
143 constant_properties,
144 is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000146 // Get the object function from the literals array. This is the
147 // object function from the context in which the function was
148 // created. We do not use the object function from the current
149 // global context because this might be the object function from
150 // another context which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000151 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152 { // Add the constant propeties to the boilerplate.
153 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000154 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
155 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 for (int index = 0; index < length; index +=2) {
157 Handle<Object> key(constant_properties->get(index+0));
158 Handle<Object> value(constant_properties->get(index+1));
159 uint32_t element_index = 0;
160 if (key->IsSymbol()) {
161 // If key is a symbol it is not an array element.
162 Handle<String> name(String::cast(*key));
163 ASSERT(!name->AsArrayIndex(&element_index));
164 SetProperty(boilerplate, name, value, NONE);
165 } else if (Array::IndexFromObject(*key, &element_index)) {
166 // Array index (uint32).
167 SetElement(boilerplate, element_index, value);
168 } else {
169 // Non-uint32 number.
170 ASSERT(key->IsNumber());
171 double num = key->Number();
172 char arr[100];
173 Vector<char> buffer(arr, ARRAY_SIZE(arr));
174 const char* str = DoubleToCString(num, buffer);
175 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
176 SetProperty(boilerplate, name, value, NONE);
177 }
178 }
179 }
180
181 // Update the functions literal and return the boilerplate.
182 literals->set(literals_index, *boilerplate);
183
184 return *boilerplate;
185}
186
187
188static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000189 // Takes a FixedArray of elements containing the literal elements of
190 // the array literal and produces JSArray with those elements.
191 // Additionally takes the literals array of the surrounding function
192 // which contains the Array function to use for creating the array
193 // literal.
194 ASSERT(args.length() == 2);
195 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000196 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000197 JSFunction* constructor =
198 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 // Create the JSArray.
200 Object* object = Heap::AllocateJSObject(constructor);
201 if (object->IsFailure()) return object;
202
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000203 // Copy the elements.
204 Object* content = elements->Copy();
205 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206
207 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000208 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 return object;
210}
211
212
213static Object* Runtime_ClassOf(Arguments args) {
214 NoHandleAllocation ha;
215 ASSERT(args.length() == 1);
216 Object* obj = args[0];
217 if (!obj->IsJSObject()) return Heap::null_value();
218 return JSObject::cast(obj)->class_name();
219}
220
221
222static Object* Runtime_IsInPrototypeChain(Arguments args) {
223 NoHandleAllocation ha;
224 ASSERT(args.length() == 2);
225 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
226 Object* O = args[0];
227 Object* V = args[1];
228 while (true) {
229 Object* prototype = V->GetPrototype();
230 if (prototype->IsNull()) return Heap::false_value();
231 if (O == prototype) return Heap::true_value();
232 V = prototype;
233 }
234}
235
236
237static Object* Runtime_IsConstructCall(Arguments args) {
238 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000239 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 JavaScriptFrameIterator it;
241 return Heap::ToBoolean(it.frame()->IsConstructor());
242}
243
244
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245static Object* Runtime_RegExpCompile(Arguments args) {
246 HandleScope scope; // create a new handle scope
247 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
249 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(String, raw_pattern, args[1]);
251 Handle<String> pattern(raw_pattern);
252 CONVERT_CHECKED(String, raw_flags, args[2]);
253 Handle<String> flags(raw_flags);
254 return *RegExpImpl::JsreCompile(re, pattern, flags);
255}
256
257
258static Object* Runtime_CreateApiFunction(Arguments args) {
259 HandleScope scope;
260 ASSERT(args.length() == 1);
261 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
262 Handle<FunctionTemplateInfo> data(raw_data);
263 return *Factory::CreateApiFunction(data);
264}
265
266
267static Object* Runtime_IsTemplate(Arguments args) {
268 ASSERT(args.length() == 1);
269 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000270 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271 return Heap::ToBoolean(result);
272}
273
274
275static Object* Runtime_GetTemplateField(Arguments args) {
276 ASSERT(args.length() == 2);
277 CONVERT_CHECKED(HeapObject, templ, args[0]);
278 RUNTIME_ASSERT(templ->IsStruct());
279 CONVERT_CHECKED(Smi, field, args[1]);
280 return HeapObject::GetHeapObjectField(templ, field->value());
281}
282
283
284static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
285 HandleScope scope;
286 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
287 Handle<Object> args[2] = { type_handle, name };
288 Handle<Object> error =
289 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
290 return Top::Throw(*error);
291}
292
293
294static Object* Runtime_DeclareGlobals(Arguments args) {
295 HandleScope scope;
296 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
297
298 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
299 Handle<Context> context = args.at<Context>(1);
300 bool is_eval = Smi::cast(args[2])->value() == 1;
301
302 // Compute the property attributes. According to ECMA-262, section
303 // 13, page 71, the property must be read-only and
304 // non-deletable. However, neither SpiderMonkey nor KJS creates the
305 // property as read-only, so we don't either.
306 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
307
308 // Only optimize the object if we intend to add more than 5 properties.
309 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
310
311 // Traverse the name/value pairs and set the properties.
312 int length = pairs->length();
313 for (int i = 0; i < length; i += 2) {
314 HandleScope scope;
315 Handle<String> name(String::cast(pairs->get(i)));
316 Handle<Object> value(pairs->get(i + 1));
317
318 // We have to declare a global const property. To capture we only
319 // assign to it when evaluating the assignment for "const x =
320 // <expr>" the initial value is the hole.
321 bool is_const_property = value->IsTheHole();
322
323 if (value->IsUndefined() || is_const_property) {
324 // Lookup the property in the global object, and don't set the
325 // value of the variable if the property is already there.
326 LookupResult lookup;
327 global->Lookup(*name, &lookup);
328 if (lookup.IsProperty()) {
329 // Determine if the property is local by comparing the holder
330 // against the global object. The information will be used to
331 // avoid throwing re-declaration errors when declaring
332 // variables or constants that exist in the prototype chain.
333 bool is_local = (*global == lookup.holder());
334 // Get the property attributes and determine if the property is
335 // read-only.
336 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
337 bool is_read_only = (attributes & READ_ONLY) != 0;
338 if (lookup.type() == INTERCEPTOR) {
339 // If the interceptor says the property is there, we
340 // just return undefined without overwriting the property.
341 // Otherwise, we continue to setting the property.
342 if (attributes != ABSENT) {
343 // Check if the existing property conflicts with regards to const.
344 if (is_local && (is_read_only || is_const_property)) {
345 const char* type = (is_read_only) ? "const" : "var";
346 return ThrowRedeclarationError(type, name);
347 };
348 // The property already exists without conflicting: Go to
349 // the next declaration.
350 continue;
351 }
352 // Fall-through and introduce the absent property by using
353 // SetProperty.
354 } else {
355 if (is_local && (is_read_only || is_const_property)) {
356 const char* type = (is_read_only) ? "const" : "var";
357 return ThrowRedeclarationError(type, name);
358 }
359 // The property already exists without conflicting: Go to
360 // the next declaration.
361 continue;
362 }
363 }
364 } else {
365 // Copy the function and update its context. Use it as value.
366 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
367 Handle<JSFunction> function =
368 Factory::NewFunctionFromBoilerplate(boilerplate, context);
369 value = function;
370 }
371
372 LookupResult lookup;
373 global->LocalLookup(*name, &lookup);
374
375 PropertyAttributes attributes = is_const_property
376 ? static_cast<PropertyAttributes>(base | READ_ONLY)
377 : base;
378
379 if (lookup.IsProperty()) {
380 // There's a local property that we need to overwrite because
381 // we're either declaring a function or there's an interceptor
382 // that claims the property is absent.
383
384 // Check for conflicting re-declarations. We cannot have
385 // conflicting types in case of intercepted properties because
386 // they are absent.
387 if (lookup.type() != INTERCEPTOR &&
388 (lookup.IsReadOnly() || is_const_property)) {
389 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
390 return ThrowRedeclarationError(type, name);
391 }
392 SetProperty(global, name, value, attributes);
393 } else {
394 // If a property with this name does not already exist on the
395 // global object add the property locally. We take special
396 // precautions to always add it as a local property even in case
397 // of callbacks in the prototype chain (this rules out using
398 // SetProperty). Also, we must use the handle-based version to
399 // avoid GC issues.
400 AddProperty(global, name, value, attributes);
401 }
402 }
403 // Done.
404 return Heap::undefined_value();
405}
406
407
408static Object* Runtime_DeclareContextSlot(Arguments args) {
409 HandleScope scope;
410 ASSERT(args.length() == 5);
411
412 // args[0] is result (TOS)
413 CONVERT_ARG_CHECKED(Context, context, 1);
414 Handle<String> name(String::cast(args[2]));
415 PropertyAttributes mode =
416 static_cast<PropertyAttributes>(Smi::cast(args[3])->value());
417 ASSERT(mode == READ_ONLY || mode == NONE);
418 Handle<Object> initial_value(args[4]);
419
420 // Declarations are always done in the function context.
421 context = Handle<Context>(context->fcontext());
422
423 int index;
424 PropertyAttributes attributes;
425 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
426 Handle<Object> context_obj =
427 context->Lookup(name, flags, &index, &attributes);
428
429 if (attributes != ABSENT) {
430 // The name was declared before; check for conflicting
431 // re-declarations: This is similar to the code in parser.cc in
432 // the AstBuildingParser::Declare function.
433 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
434 // Functions are not read-only.
435 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
436 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
437 return ThrowRedeclarationError(type, name);
438 }
439
440 // Initialize it if necessary.
441 if (*initial_value != NULL) {
442 if (index >= 0) {
443 // The variable or constant context slot should always be in
444 // the function context; not in any outer context nor in the
445 // arguments object.
446 ASSERT(context_obj.is_identical_to(context));
447 if (((attributes & READ_ONLY) == 0) ||
448 context->get(index)->IsTheHole()) {
449 context->set(index, *initial_value);
450 }
451 } else {
452 // Slow case: The property is not in the FixedArray part of the context.
453 Handle<JSObject> context_ext = Handle<JSObject>::cast(context_obj);
454 SetProperty(context_ext, name, initial_value, mode);
455 }
456 }
457 return args[0]; // return TOS
458 }
459
460 // The property is not in the function context. It needs to be "declared"
461 // in the function context's extension context, or in the global context.
462 Handle<JSObject> context_ext;
463 if (context->extension() != NULL) {
464 // The function context's extension context exists - use it.
465 context_ext = Handle<JSObject>(context->extension());
466 } else {
467 // The function context's extension context does not exists - allocate it.
468 context_ext = Factory::NewJSObject(Top::context_extension_function());
469 // And store it in the extension slot.
470 context->set_extension(*context_ext);
471 }
472 ASSERT(*context_ext != NULL);
473
474 // Declare the property by setting it to the initial value if provided,
475 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
476 // constant declarations).
477 ASSERT(!context_ext->HasLocalProperty(*name));
478 Handle<Object> value(Heap::undefined_value());
479 if (*initial_value != NULL) value = initial_value;
480 SetProperty(context_ext, name, value, mode);
481 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
482 return args[0]; // return TOS
483}
484
485
486static Object* Runtime_InitializeVarGlobal(Arguments args) {
487 NoHandleAllocation nha;
488
489 // Determine if we need to assign to the variable if it already
490 // exists (based on the number of arguments).
491 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
492 bool assign = args.length() == 2;
493
494 CONVERT_ARG_CHECKED(String, name, 0);
495 GlobalObject* global = Top::context()->global();
496
497 // According to ECMA-262, section 12.2, page 62, the property must
498 // not be deletable.
499 PropertyAttributes attributes = DONT_DELETE;
500
501 // Lookup the property locally in the global object. If it isn't
502 // there, we add the property and take special precautions to always
503 // add it as a local property even in case of callbacks in the
504 // prototype chain (this rules out using SetProperty).
505 LookupResult lookup;
506 global->LocalLookup(*name, &lookup);
507 if (!lookup.IsProperty()) {
508 Object* value = (assign) ? args[1] : Heap::undefined_value();
509 return global->AddProperty(*name, value, attributes);
510 }
511
512 // Determine if this is a redeclaration of something read-only.
513 if (lookup.IsReadOnly()) {
514 return ThrowRedeclarationError("const", name);
515 }
516
517 // Determine if this is a redeclaration of an intercepted read-only
518 // property and figure out if the property exists at all.
519 bool found = true;
520 PropertyType type = lookup.type();
521 if (type == INTERCEPTOR) {
522 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
523 if (intercepted == ABSENT) {
524 // The interceptor claims the property isn't there. We need to
525 // make sure to introduce it.
526 found = false;
527 } else if ((intercepted & READ_ONLY) != 0) {
528 // The property is present, but read-only. Since we're trying to
529 // overwrite it with a variable declaration we must throw a
530 // re-declaration error.
531 return ThrowRedeclarationError("const", name);
532 }
533 // Restore global object from context (in case of GC).
534 global = Top::context()->global();
535 }
536
537 if (found && !assign) {
538 // The global property is there and we're not assigning any value
539 // to it. Just return.
540 return Heap::undefined_value();
541 }
542
543 // Assign the value (or undefined) to the property.
544 Object* value = (assign) ? args[1] : Heap::undefined_value();
545 return global->SetProperty(&lookup, *name, value, attributes);
546}
547
548
549static Object* Runtime_InitializeConstGlobal(Arguments args) {
550 // All constants are declared with an initial value. The name
551 // of the constant is the first argument and the initial value
552 // is the second.
553 RUNTIME_ASSERT(args.length() == 2);
554 CONVERT_ARG_CHECKED(String, name, 0);
555 Handle<Object> value = args.at<Object>(1);
556
557 // Get the current global object from top.
558 GlobalObject* global = Top::context()->global();
559
560 // According to ECMA-262, section 12.2, page 62, the property must
561 // not be deletable. Since it's a const, it must be READ_ONLY too.
562 PropertyAttributes attributes =
563 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
564
565 // Lookup the property locally in the global object. If it isn't
566 // there, we add the property and take special precautions to always
567 // add it as a local property even in case of callbacks in the
568 // prototype chain (this rules out using SetProperty).
569 LookupResult lookup;
570 global->LocalLookup(*name, &lookup);
571 if (!lookup.IsProperty()) {
572 return global->AddProperty(*name, *value, attributes);
573 }
574
575 // Determine if this is a redeclaration of something not
576 // read-only. In case the result is hidden behind an interceptor we
577 // need to ask it for the property attributes.
578 if (!lookup.IsReadOnly()) {
579 if (lookup.type() != INTERCEPTOR) {
580 return ThrowRedeclarationError("var", name);
581 }
582
583 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
584
585 // Throw re-declaration error if the intercepted property is present
586 // but not read-only.
587 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
588 return ThrowRedeclarationError("var", name);
589 }
590
591 // Restore global object from context (in case of GC) and continue
592 // with setting the value because the property is either absent or
593 // read-only. We also have to do redo the lookup.
594 global = Top::context()->global();
595
596 // BUG 1213579: Handle the case where we have to set a read-only
597 // property through an interceptor and only do it if it's
598 // uninitialized, e.g. the hole. Nirk...
599 global->SetProperty(*name, *value, attributes);
600 return *value;
601 }
602
603 // Set the value, but only we're assigning the initial value to a
604 // constant. For now, we determine this by checking if the
605 // current value is the hole.
606 PropertyType type = lookup.type();
607 if (type == FIELD) {
608 FixedArray* properties = global->properties();
609 int index = lookup.GetFieldIndex();
610 if (properties->get(index)->IsTheHole()) {
611 properties->set(index, *value);
612 }
613 } else if (type == NORMAL) {
614 Dictionary* dictionary = global->property_dictionary();
615 int entry = lookup.GetDictionaryEntry();
616 if (dictionary->ValueAt(entry)->IsTheHole()) {
617 dictionary->ValueAtPut(entry, *value);
618 }
619 } else {
620 // Ignore re-initialization of constants that have already been
621 // assigned a function value.
622 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
623 }
624
625 // Use the set value as the result of the operation.
626 return *value;
627}
628
629
630static Object* Runtime_InitializeConstContextSlot(Arguments args) {
631 HandleScope scope;
632 ASSERT(args.length() == 3);
633
634 Handle<Object> value(args[0]);
635 ASSERT(!value->IsTheHole());
636 CONVERT_ARG_CHECKED(Context, context, 1);
637 Handle<String> name(String::cast(args[2]));
638
639 // Initializations are always done in the function context.
640 context = Handle<Context>(context->fcontext());
641
642 int index;
643 PropertyAttributes attributes;
644 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
645 Handle<Object> context_obj =
646 context->Lookup(name, flags, &index, &attributes);
647
648 // The property should always be present. It is always declared
649 // before being initialized through DeclareContextSlot.
650 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
651
652 // If the slot is in the context, we set it but only if it hasn't
653 // been set before.
654 if (index >= 0) {
655 // The constant context slot should always be in the function
656 // context; not in any outer context nor in the arguments object.
657 ASSERT(context_obj.is_identical_to(context));
658 if (context->get(index)->IsTheHole()) {
659 context->set(index, *value);
660 }
661 return *value;
662 }
663
664 // Otherwise, the slot must be in a JS object extension.
665 Handle<JSObject> context_ext(JSObject::cast(*context_obj));
666
667 // We must initialize the value only if it wasn't initialized
668 // before, e.g. for const declarations in a loop. The property has
669 // the hole value if it wasn't initialized yet. NOTE: We cannot use
670 // GetProperty() to get the current value as it 'unholes' the value.
671 LookupResult lookup;
672 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
673 ASSERT(lookup.IsProperty()); // the property was declared
674 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
675
676 PropertyType type = lookup.type();
677 if (type == FIELD) {
678 FixedArray* properties = context_ext->properties();
679 int index = lookup.GetFieldIndex();
680 if (properties->get(index)->IsTheHole()) {
681 properties->set(index, *value);
682 }
683 } else if (type == NORMAL) {
684 Dictionary* dictionary = context_ext->property_dictionary();
685 int entry = lookup.GetDictionaryEntry();
686 if (dictionary->ValueAt(entry)->IsTheHole()) {
687 dictionary->ValueAtPut(entry, *value);
688 }
689 } else {
690 // We should not reach here. Any real, named property should be
691 // either a field or a dictionary slot.
692 UNREACHABLE();
693 }
694 return *value;
695}
696
697
698static Object* Runtime_RegExpExec(Arguments args) {
699 HandleScope scope;
700 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000701 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
702 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703 CONVERT_CHECKED(String, raw_subject, args[1]);
704 Handle<String> subject(raw_subject);
705 Handle<Object> index(args[2]);
706 ASSERT(index->IsNumber());
707 return *RegExpImpl::JsreExec(regexp, subject, index);
708}
709
710
711static Object* Runtime_RegExpExecGlobal(Arguments args) {
712 HandleScope scope;
713 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000714 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
715 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 CONVERT_CHECKED(String, raw_subject, args[1]);
717 Handle<String> subject(raw_subject);
718 return *RegExpImpl::JsreExecGlobal(regexp, subject);
719}
720
721
722static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
723 HandleScope scope;
724 ASSERT(args.length() == 4);
725 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
726 int index = Smi::cast(args[1])->value();
727 Handle<String> pattern = args.at<String>(2);
728 Handle<String> flags = args.at<String>(3);
729
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730 // Get the RegExp function from the literals array. This is the
731 // RegExp function from the context in which the function was
732 // created. We do not use the RegExp function from the current
733 // global context because this might be the RegExp function from
734 // another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000736 Handle<JSFunction>(
737 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738 // Compute the regular expression literal.
739 bool has_pending_exception;
740 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000741 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
742 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 if (has_pending_exception) {
744 ASSERT(Top::has_pending_exception());
745 return Failure::Exception();
746 }
747 literals->set(index, *regexp);
748 return *regexp;
749}
750
751
752static Object* Runtime_FunctionGetName(Arguments args) {
753 NoHandleAllocation ha;
754 ASSERT(args.length() == 1);
755
756 CONVERT_CHECKED(JSFunction, f, args[0]);
757 return f->shared()->name();
758}
759
760
ager@chromium.org236ad962008-09-25 09:45:57 +0000761static Object* Runtime_FunctionSetName(Arguments args) {
762 NoHandleAllocation ha;
763 ASSERT(args.length() == 2);
764
765 CONVERT_CHECKED(JSFunction, f, args[0]);
766 CONVERT_CHECKED(String, name, args[1]);
767 f->shared()->set_name(name);
768 return Heap::undefined_value();
769}
770
771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772static Object* Runtime_FunctionGetScript(Arguments args) {
773 HandleScope scope;
774 ASSERT(args.length() == 1);
775
776 CONVERT_CHECKED(JSFunction, fun, args[0]);
777 Handle<Object> script = Handle<Object>(fun->shared()->script());
778 if (!script->IsScript()) return Heap::undefined_value();
779
780 return *GetScriptWrapper(Handle<Script>::cast(script));
781}
782
783
784static Object* Runtime_FunctionGetSourceCode(Arguments args) {
785 NoHandleAllocation ha;
786 ASSERT(args.length() == 1);
787
788 CONVERT_CHECKED(JSFunction, f, args[0]);
789 return f->shared()->GetSourceCode();
790}
791
792
793static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
794 NoHandleAllocation ha;
795 ASSERT(args.length() == 1);
796
797 CONVERT_CHECKED(JSFunction, fun, args[0]);
798 int pos = fun->shared()->start_position();
799 return Smi::FromInt(pos);
800}
801
802
803static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
804 NoHandleAllocation ha;
805 ASSERT(args.length() == 2);
806
807 CONVERT_CHECKED(JSFunction, fun, args[0]);
808 CONVERT_CHECKED(String, name, args[1]);
809 fun->SetInstanceClassName(name);
810 return Heap::undefined_value();
811}
812
813
814static Object* Runtime_FunctionSetLength(Arguments args) {
815 NoHandleAllocation ha;
816 ASSERT(args.length() == 2);
817
818 CONVERT_CHECKED(JSFunction, fun, args[0]);
819 CONVERT_CHECKED(Smi, length, args[1]);
820 fun->shared()->set_length(length->value());
821 return length;
822}
823
824
825static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 ASSERT(args.length() == 2);
828
829 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000830 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
831 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 return args[0]; // return TOS
833}
834
835
836static Object* Runtime_SetCode(Arguments args) {
837 HandleScope scope;
838 ASSERT(args.length() == 2);
839
840 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
841 Handle<JSFunction> target(raw_target);
842 Handle<Object> code = args.at<Object>(1);
843
844 Handle<Context> context(target->context());
845
846 if (!code->IsNull()) {
847 RUNTIME_ASSERT(code->IsJSFunction());
848 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
849 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
850 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
851 return Failure::Exception();
852 }
853 // Set the code, formal parameter count, and the length of the target
854 // function.
855 target->set_code(fun->code());
856 target->shared()->set_length(fun->shared()->length());
857 target->shared()->set_formal_parameter_count(
858 fun->shared()->formal_parameter_count());
kasper.lund7276f142008-07-30 08:49:36 +0000859 // Set the source code of the target function.
860 target->shared()->set_script(fun->shared()->script());
861 target->shared()->set_start_position(fun->shared()->start_position());
862 target->shared()->set_end_position(fun->shared()->end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 context = Handle<Context>(fun->context());
864
865 // Make sure we get a fresh copy of the literal vector to avoid
866 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000867 int number_of_literals = fun->NumberOfLiterals();
868 Handle<FixedArray> literals =
869 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000871 // Insert the object, regexp and array functions in the literals
872 // array prefix. These are the functions that will be used when
873 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +0000874 literals->set(JSFunction::kLiteralGlobalContextIndex,
875 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000877 target->set_literals(*literals);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 }
879
880 target->set_context(*context);
881 return *target;
882}
883
884
885static Object* CharCodeAt(String* subject, Object* index) {
886 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000887 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888 // Flatten the string. If someone wants to get a char at an index
889 // in a cons string, it is likely that more indices will be
890 // accessed.
891 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000892 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893 return Smi::FromInt(subject->Get(i));
894}
895
896
897static Object* Runtime_StringCharCodeAt(Arguments args) {
898 NoHandleAllocation ha;
899 ASSERT(args.length() == 2);
900
901 CONVERT_CHECKED(String, subject, args[0]);
902 Object* index = args[1];
903 return CharCodeAt(subject, index);
904}
905
906
907static Object* Runtime_CharFromCode(Arguments args) {
908 NoHandleAllocation ha;
909 ASSERT(args.length() == 1);
910 uint32_t code;
911 if (Array::IndexFromObject(args[0], &code)) {
912 if (code <= 0xffff) {
913 return Heap::LookupSingleCharacterStringFromCode(code);
914 }
915 }
916 return Heap::empty_string();
917}
918
919
920static inline void ComputeKMPNextTable(String* pattern, int next_table[]) {
921 int i = 0;
922 int j = -1;
923 next_table[0] = -1;
924
925 Access<StringInputBuffer> buffer(&string_input_buffer);
926 buffer->Reset(pattern);
927 int length = pattern->length();
928 uint16_t p = buffer->GetNext();
929 while (i < length - 1) {
930 while (j > -1 && p != pattern->Get(j)) {
931 j = next_table[j];
932 }
933 i++;
934 j++;
935 p = buffer->GetNext();
936 if (p == pattern->Get(j)) {
937 next_table[i] = next_table[j];
938 } else {
939 next_table[i] = j;
940 }
941 }
942}
943
944
945static Object* Runtime_StringIndexOf(Arguments args) {
946 NoHandleAllocation ha;
947 ASSERT(args.length() == 3);
948
949 CONVERT_CHECKED(String, sub, args[0]);
950 CONVERT_CHECKED(String, pat, args[1]);
951 Object* index = args[2];
952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953 sub->TryFlatten();
954 pat->TryFlatten();
955
ager@chromium.org236ad962008-09-25 09:45:57 +0000956 int subject_length = sub->length();
957 int pattern_length = pat->length();
958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 uint32_t start_index;
960 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
961 if (pattern_length == 0) return Smi::FromInt(start_index);
962
963 // Searching for one specific character is common. For one
964 // character patterns the KMP algorithm is guaranteed to slow down
965 // the search, so we just run through the subject string.
966 if (pattern_length == 1) {
967 uint16_t pattern_char = pat->Get(0);
968 for (int i = start_index; i < subject_length; i++) {
969 if (sub->Get(i) == pattern_char) {
970 return Smi::FromInt(i);
971 }
972 }
973 return Smi::FromInt(-1);
974 }
975
ager@chromium.org236ad962008-09-25 09:45:57 +0000976 // For small searches, KMP is not worth the setup overhead.
977 if (subject_length < 100) {
978 // We know our pattern is at least 2 characters, we cache the first so
979 // the common case of the first character not matching is faster.
980 uint16_t pattern_first_char = pat->Get(0);
981 for (int i = start_index; i + pattern_length <= subject_length; i++) {
982 if (sub->Get(i) != pattern_first_char) continue;
983
984 for (int j = 1; j < pattern_length; j++) {
985 if (pat->Get(j) != sub->Get(j + i)) break;
986 if (j == pattern_length - 1) return Smi::FromInt(i);
987 }
988 }
989 return Smi::FromInt(-1);
990 }
991
992 // For patterns with a larger length we use the KMP algorithm.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 //
994 // Compute the 'next' table.
995 int* next_table = NewArray<int>(pattern_length);
996 ComputeKMPNextTable(pat, next_table);
997 // Search using the 'next' table.
998 int pattern_index = 0;
999 // We would like to use StringInputBuffer here, but it does not have
1000 // the ability to start anywhere but the first character of a
1001 // string. It would be nice to have efficient forward-seeking
1002 // support on StringInputBuffers.
1003 int subject_index = start_index;
1004 while (subject_index < subject_length) {
1005 uint16_t subject_char = sub->Get(subject_index);
1006 while (pattern_index > -1 && pat->Get(pattern_index) != subject_char) {
1007 pattern_index = next_table[pattern_index];
1008 }
1009 pattern_index++;
1010 subject_index++;
1011 if (pattern_index >= pattern_length) {
1012 DeleteArray(next_table);
1013 return Smi::FromInt(subject_index - pattern_index);
1014 }
1015 }
1016 DeleteArray(next_table);
1017 return Smi::FromInt(-1);
1018}
1019
1020
1021static Object* Runtime_StringLastIndexOf(Arguments args) {
1022 NoHandleAllocation ha;
1023 ASSERT(args.length() == 3);
1024
1025 CONVERT_CHECKED(String, sub, args[0]);
1026 CONVERT_CHECKED(String, pat, args[1]);
1027 Object* index = args[2];
1028
1029 sub->TryFlatten();
1030 pat->TryFlatten();
1031
1032 uint32_t start_index;
1033 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1034
1035 uint32_t pattern_length = pat->length();
1036 uint32_t sub_length = sub->length();
1037
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001038 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041
1042 for (int i = start_index; i >= 0; i--) {
1043 bool found = true;
1044 for (uint32_t j = 0; j < pattern_length; j++) {
1045 if (sub->Get(i + j) != pat->Get(j)) {
1046 found = false;
1047 break;
1048 }
1049 }
1050 if (found) return Smi::FromInt(i);
1051 }
1052
1053 return Smi::FromInt(-1);
1054}
1055
1056
1057static Object* Runtime_StringLocaleCompare(Arguments args) {
1058 NoHandleAllocation ha;
1059 ASSERT(args.length() == 2);
1060
1061 CONVERT_CHECKED(String, str1, args[0]);
1062 CONVERT_CHECKED(String, str2, args[1]);
1063
1064 if (str1 == str2) return Smi::FromInt(0); // Equal.
1065 int str1_length = str1->length();
1066 int str2_length = str2->length();
1067
1068 // Decide trivial cases without flattening.
1069 if (str1_length == 0) {
1070 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1071 return Smi::FromInt(-str2_length);
1072 } else {
1073 if (str2_length == 0) return Smi::FromInt(str1_length);
1074 }
1075
1076 int end = str1_length < str2_length ? str1_length : str2_length;
1077
1078 // No need to flatten if we are going to find the answer on the first
1079 // character. At this point we know there is at least one character
1080 // in each string, due to the trivial case handling above.
1081 int d = str1->Get(0) - str2->Get(0);
1082 if (d != 0) return Smi::FromInt(d);
1083
1084 str1->TryFlatten();
1085 str2->TryFlatten();
1086
1087 static StringInputBuffer buf1;
1088 static StringInputBuffer buf2;
1089
1090 buf1.Reset(str1);
1091 buf2.Reset(str2);
1092
1093 for (int i = 0; i < end; i++) {
1094 uint16_t char1 = buf1.GetNext();
1095 uint16_t char2 = buf2.GetNext();
1096 if (char1 != char2) return Smi::FromInt(char1 - char2);
1097 }
1098
1099 return Smi::FromInt(str1_length - str2_length);
1100}
1101
1102
1103static Object* Runtime_StringSlice(Arguments args) {
1104 NoHandleAllocation ha;
1105 ASSERT(args.length() == 3);
1106
1107 CONVERT_CHECKED(String, value, args[0]);
1108 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1109 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1110
1111 int start = FastD2I(from_number);
1112 int end = FastD2I(to_number);
1113
1114 RUNTIME_ASSERT(end >= start);
1115 RUNTIME_ASSERT(start >= 0);
1116 RUNTIME_ASSERT(end <= value->length());
1117 return value->Slice(start, end);
1118}
1119
1120
1121static Object* Runtime_NumberToRadixString(Arguments args) {
1122 NoHandleAllocation ha;
1123 ASSERT(args.length() == 2);
1124
1125 CONVERT_DOUBLE_CHECKED(value, args[0]);
1126 if (isnan(value)) {
1127 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1128 }
1129 if (isinf(value)) {
1130 if (value < 0) {
1131 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1132 }
1133 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1134 }
1135 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1136 int radix = FastD2I(radix_number);
1137 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1138 char* str = DoubleToRadixCString(value, radix);
1139 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1140 DeleteArray(str);
1141 return result;
1142}
1143
1144
1145static Object* Runtime_NumberToFixed(Arguments args) {
1146 NoHandleAllocation ha;
1147 ASSERT(args.length() == 2);
1148
1149 CONVERT_DOUBLE_CHECKED(value, args[0]);
1150 if (isnan(value)) {
1151 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1152 }
1153 if (isinf(value)) {
1154 if (value < 0) {
1155 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1156 }
1157 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1158 }
1159 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1160 int f = FastD2I(f_number);
1161 RUNTIME_ASSERT(f >= 0);
1162 char* str = DoubleToFixedCString(value, f);
1163 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1164 DeleteArray(str);
1165 return res;
1166}
1167
1168
1169static Object* Runtime_NumberToExponential(Arguments args) {
1170 NoHandleAllocation ha;
1171 ASSERT(args.length() == 2);
1172
1173 CONVERT_DOUBLE_CHECKED(value, args[0]);
1174 if (isnan(value)) {
1175 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1176 }
1177 if (isinf(value)) {
1178 if (value < 0) {
1179 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1180 }
1181 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1182 }
1183 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1184 int f = FastD2I(f_number);
1185 RUNTIME_ASSERT(f >= -1 && f <= 20);
1186 char* str = DoubleToExponentialCString(value, f);
1187 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1188 DeleteArray(str);
1189 return res;
1190}
1191
1192
1193static Object* Runtime_NumberToPrecision(Arguments args) {
1194 NoHandleAllocation ha;
1195 ASSERT(args.length() == 2);
1196
1197 CONVERT_DOUBLE_CHECKED(value, args[0]);
1198 if (isnan(value)) {
1199 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1200 }
1201 if (isinf(value)) {
1202 if (value < 0) {
1203 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1204 }
1205 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1206 }
1207 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1208 int f = FastD2I(f_number);
1209 RUNTIME_ASSERT(f >= 1 && f <= 21);
1210 char* str = DoubleToPrecisionCString(value, f);
1211 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1212 DeleteArray(str);
1213 return res;
1214}
1215
1216
1217// Returns a single character string where first character equals
1218// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001219static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220 if (index < static_cast<uint32_t>(string->length())) {
1221 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001222 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001224 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225}
1226
1227
1228Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1229 // Handle [] indexing on Strings
1230 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001231 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1232 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233 }
1234
1235 // Handle [] indexing on String objects
1236 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001237 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1238 Handle<Object> result =
1239 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1240 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242
1243 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001244 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 return prototype->GetElement(index);
1246 }
1247
1248 return object->GetElement(index);
1249}
1250
1251
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001252Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1253 HandleScope scope;
1254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001256 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 Handle<Object> error =
1258 Factory::NewTypeError("non_object_property_load",
1259 HandleVector(args, 2));
1260 return Top::Throw(*error);
1261 }
1262
1263 // Check if the given key is an array index.
1264 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001265 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 return GetElementOrCharAt(object, index);
1267 }
1268
1269 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001270 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001272 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 bool has_pending_exception = false;
1275 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001276 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001278 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 }
1280
1281 // Check if the name is trivially convertable to an index and get
1282 // the element if so.
1283 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 return GetElementOrCharAt(object, index);
1285 } else {
1286 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001287 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 }
1289}
1290
1291
1292static Object* Runtime_GetProperty(Arguments args) {
1293 NoHandleAllocation ha;
1294 ASSERT(args.length() == 2);
1295
1296 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001297 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
1299 return Runtime::GetObjectProperty(object, key);
1300}
1301
1302
1303Object* Runtime::SetObjectProperty(Handle<Object> object,
1304 Handle<Object> key,
1305 Handle<Object> value,
1306 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001307 HandleScope scope;
1308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001310 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 Handle<Object> error =
1312 Factory::NewTypeError("non_object_property_store",
1313 HandleVector(args, 2));
1314 return Top::Throw(*error);
1315 }
1316
1317 // If the object isn't a JavaScript object, we ignore the store.
1318 if (!object->IsJSObject()) return *value;
1319
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001320 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1321
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322 // Check if the given key is an array index.
1323 uint32_t index;
1324 if (Array::IndexFromObject(*key, &index)) {
1325 ASSERT(attr == NONE);
1326
1327 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1328 // of a string using [] notation. We need to support this too in
1329 // JavaScript.
1330 // In the case of a String object we just need to redirect the assignment to
1331 // the underlying string if the index is in range. Since the underlying
1332 // string does nothing with the assignment then we can ignore such
1333 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001334 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001338 Handle<Object> result = SetElement(js_object, index, value);
1339 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 return *value;
1341 }
1342
1343 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001344 Handle<Object> result;
1345 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001347 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001349 Handle<String> key_string = Handle<String>::cast(key);
1350 key_string->TryFlatten();
1351 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001353 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 return *value;
1355 }
1356
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 bool has_pending_exception = false;
1359 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1360 if (has_pending_exception) return Failure::Exception();
1361 Handle<String> name = Handle<String>::cast(converted);
1362
1363 if (name->AsArrayIndex(&index)) {
1364 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001365 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001367 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 }
1369}
1370
1371
1372static Object* Runtime_AddProperty(Arguments args) {
1373 NoHandleAllocation ha;
1374 ASSERT(args.length() == 4);
1375
1376 CONVERT_CHECKED(JSObject, object, args[0]);
1377 CONVERT_CHECKED(String, name, args[1]);
1378 RUNTIME_ASSERT(!object->HasLocalProperty(name));
1379 CONVERT_CHECKED(Smi, attr_obj, args[3]);
1380
1381 int attr = attr_obj->value();
1382 RUNTIME_ASSERT((attr & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1383 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1384
1385 return object->AddProperty(name, args[2], attributes);
1386}
1387
1388
1389static Object* Runtime_SetProperty(Arguments args) {
1390 NoHandleAllocation ha;
1391 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1392
1393 Handle<Object> object = args.at<Object>(0);
1394 Handle<Object> key = args.at<Object>(1);
1395 Handle<Object> value = args.at<Object>(2);
1396
1397 // Compute attributes.
1398 PropertyAttributes attributes = NONE;
1399 if (args.length() == 4) {
1400 CONVERT_CHECKED(Smi, value_obj, args[3]);
1401 int value = value_obj->value();
1402 // Only attribute bits should be set.
1403 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1404 attributes = static_cast<PropertyAttributes>(value);
1405 }
1406 return Runtime::SetObjectProperty(object, key, value, attributes);
1407}
1408
1409
1410// Set a local property, even if it is READ_ONLY. If the property does not
1411// exist, it will be added with attributes NONE.
1412static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1413 NoHandleAllocation ha;
1414 ASSERT(args.length() == 3);
1415
1416 CONVERT_CHECKED(JSObject, object, args[0]);
1417 CONVERT_CHECKED(String, name, args[1]);
1418
1419 return object->IgnoreAttributesAndSetLocalProperty(name, args[2]);
1420}
1421
1422
1423static Object* Runtime_DeleteProperty(Arguments args) {
1424 NoHandleAllocation ha;
1425 ASSERT(args.length() == 2);
1426
1427 CONVERT_CHECKED(JSObject, object, args[0]);
1428 CONVERT_CHECKED(String, key, args[1]);
1429 return object->DeleteProperty(key);
1430}
1431
1432
1433static Object* Runtime_HasLocalProperty(Arguments args) {
1434 NoHandleAllocation ha;
1435 ASSERT(args.length() == 2);
1436 CONVERT_CHECKED(String, key, args[1]);
1437
1438 // Only JS objects can have properties.
1439 if (args[0]->IsJSObject()) {
1440 JSObject* object = JSObject::cast(args[0]);
1441 if (object->HasLocalProperty(key)) return Heap::true_value();
1442 } else if (args[0]->IsString()) {
1443 // Well, there is one exception: Handle [] on strings.
1444 uint32_t index;
1445 if (key->AsArrayIndex(&index)) {
1446 String* string = String::cast(args[0]);
1447 if (index < static_cast<uint32_t>(string->length()))
1448 return Heap::true_value();
1449 }
1450 }
1451 return Heap::false_value();
1452}
1453
1454
1455static Object* Runtime_HasProperty(Arguments args) {
1456 NoHandleAllocation na;
1457 ASSERT(args.length() == 2);
1458
1459 // Only JS objects can have properties.
1460 if (args[0]->IsJSObject()) {
1461 JSObject* object = JSObject::cast(args[0]);
1462 CONVERT_CHECKED(String, key, args[1]);
1463 if (object->HasProperty(key)) return Heap::true_value();
1464 }
1465 return Heap::false_value();
1466}
1467
1468
1469static Object* Runtime_HasElement(Arguments args) {
1470 NoHandleAllocation na;
1471 ASSERT(args.length() == 2);
1472
1473 // Only JS objects can have elements.
1474 if (args[0]->IsJSObject()) {
1475 JSObject* object = JSObject::cast(args[0]);
1476 CONVERT_CHECKED(Smi, index_obj, args[1]);
1477 uint32_t index = index_obj->value();
1478 if (object->HasElement(index)) return Heap::true_value();
1479 }
1480 return Heap::false_value();
1481}
1482
1483
1484static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1485 NoHandleAllocation ha;
1486 ASSERT(args.length() == 2);
1487
1488 CONVERT_CHECKED(JSObject, object, args[0]);
1489 CONVERT_CHECKED(String, key, args[1]);
1490
1491 uint32_t index;
1492 if (key->AsArrayIndex(&index)) {
1493 return Heap::ToBoolean(object->HasElement(index));
1494 }
1495
1496 LookupResult result;
1497 object->LocalLookup(key, &result);
1498 if (!result.IsProperty()) return Heap::false_value();
1499 return Heap::ToBoolean(!result.IsDontEnum());
1500}
1501
1502
1503static Object* Runtime_GetPropertyNames(Arguments args) {
1504 HandleScope scope;
1505 ASSERT(args.length() == 1);
1506
1507 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1508 Handle<JSObject> object(raw_object);
1509 return *GetKeysFor(object);
1510}
1511
1512
1513// Returns either a FixedArray as Runtime_GetPropertyNames,
1514// or, if the given object has an enum cache that contains
1515// all enumerable properties of the object and its prototypes
1516// have none, the map of the object. This is used to speed up
1517// the check for deletions during a for-in.
1518static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1519 ASSERT(args.length() == 1);
1520
1521 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1522
1523 if (raw_object->IsSimpleEnum()) return raw_object->map();
1524
1525 HandleScope scope;
1526 Handle<JSObject> object(raw_object);
1527 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1528
1529 // Test again, since cache may have been built by preceding call.
1530 if (object->IsSimpleEnum()) return object->map();
1531
1532 return *content;
1533}
1534
1535
1536static Object* Runtime_GetArgumentsProperty(Arguments args) {
1537 NoHandleAllocation ha;
1538 ASSERT(args.length() == 1);
1539
1540 // Compute the frame holding the arguments.
1541 JavaScriptFrameIterator it;
1542 it.AdvanceToArgumentsFrame();
1543 JavaScriptFrame* frame = it.frame();
1544
1545 // Get the actual number of provided arguments.
1546 const uint32_t n = frame->GetProvidedParametersCount();
1547
1548 // Try to convert the key to an index. If successful and within
1549 // index return the the argument from the frame.
1550 uint32_t index;
1551 if (Array::IndexFromObject(args[0], &index) && index < n) {
1552 return frame->GetParameter(index);
1553 }
1554
1555 // Convert the key to a string.
1556 HandleScope scope;
1557 bool exception = false;
1558 Handle<Object> converted =
1559 Execution::ToString(args.at<Object>(0), &exception);
1560 if (exception) return Failure::Exception();
1561 Handle<String> key = Handle<String>::cast(converted);
1562
1563 // Try to convert the string key into an array index.
1564 if (key->AsArrayIndex(&index)) {
1565 if (index < n) {
1566 return frame->GetParameter(index);
1567 } else {
1568 return Top::initial_object_prototype()->GetElement(index);
1569 }
1570 }
1571
1572 // Handle special arguments properties.
1573 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1574 if (key->Equals(Heap::callee_symbol())) return frame->function();
1575
1576 // Lookup in the initial Object.prototype object.
1577 return Top::initial_object_prototype()->GetProperty(*key);
1578}
1579
1580
1581static Object* Runtime_ToBool(Arguments args) {
1582 NoHandleAllocation ha;
1583 ASSERT(args.length() == 1);
1584
1585 return args[0]->ToBoolean();
1586}
1587
1588
1589// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1590// Possible optimizations: put the type string into the oddballs.
1591static Object* Runtime_Typeof(Arguments args) {
1592 NoHandleAllocation ha;
1593
1594 Object* obj = args[0];
1595 if (obj->IsNumber()) return Heap::number_symbol();
1596 HeapObject* heap_obj = HeapObject::cast(obj);
1597
1598 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001599 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600
1601 InstanceType instance_type = heap_obj->map()->instance_type();
1602 if (instance_type < FIRST_NONSTRING_TYPE) {
1603 return Heap::string_symbol();
1604 }
1605
1606 switch (instance_type) {
1607 case ODDBALL_TYPE:
1608 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1609 return Heap::boolean_symbol();
1610 }
1611 if (heap_obj->IsNull()) {
1612 return Heap::object_symbol();
1613 }
1614 ASSERT(heap_obj->IsUndefined());
1615 return Heap::undefined_symbol();
1616 case JS_FUNCTION_TYPE:
1617 return Heap::function_symbol();
1618 default:
1619 // For any kind of object not handled above, the spec rule for
1620 // host objects gives that it is okay to return "object"
1621 return Heap::object_symbol();
1622 }
1623}
1624
1625
1626static Object* Runtime_StringToNumber(Arguments args) {
1627 NoHandleAllocation ha;
1628 ASSERT(args.length() == 1);
1629 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001630 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
1632}
1633
1634
1635static Object* Runtime_StringFromCharCodeArray(Arguments args) {
1636 NoHandleAllocation ha;
1637 ASSERT(args.length() == 1);
1638
1639 CONVERT_CHECKED(JSArray, codes, args[0]);
1640 int length = Smi::cast(codes->length())->value();
1641
1642 // Check if the string can be ASCII.
1643 int i;
1644 for (i = 0; i < length; i++) {
1645 Object* element = codes->GetElement(i);
1646 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1647 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
1648 break;
1649 }
1650
1651 Object* object = NULL;
1652 if (i == length) { // The string is ASCII.
1653 object = Heap::AllocateRawAsciiString(length);
1654 } else { // The string is not ASCII.
1655 object = Heap::AllocateRawTwoByteString(length);
1656 }
1657
1658 if (object->IsFailure()) return object;
1659 String* result = String::cast(object);
1660 for (int i = 0; i < length; i++) {
1661 Object* element = codes->GetElement(i);
1662 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1663 result->Set(i, chr & 0xffff);
1664 }
1665 return result;
1666}
1667
1668
1669// kNotEscaped is generated by the following:
1670//
1671// #!/bin/perl
1672// for (my $i = 0; $i < 256; $i++) {
1673// print "\n" if $i % 16 == 0;
1674// my $c = chr($i);
1675// my $escaped = 1;
1676// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
1677// print $escaped ? "0, " : "1, ";
1678// }
1679
1680
1681static bool IsNotEscaped(uint16_t character) {
1682 // Only for 8 bit characters, the rest are always escaped (in a different way)
1683 ASSERT(character < 256);
1684 static const char kNotEscaped[256] = {
1685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1686 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1687 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
1688 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1689 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1690 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1691 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1692 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1694 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1695 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1697 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1698 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1699 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1700 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1701 };
1702 return kNotEscaped[character] != 0;
1703}
1704
1705
1706static Object* Runtime_URIEscape(Arguments args) {
1707 const char hex_chars[] = "0123456789ABCDEF";
1708 NoHandleAllocation ha;
1709 ASSERT(args.length() == 1);
1710 CONVERT_CHECKED(String, source, args[0]);
1711
1712 source->TryFlatten();
1713
1714 int escaped_length = 0;
1715 int length = source->length();
1716 {
1717 Access<StringInputBuffer> buffer(&string_input_buffer);
1718 buffer->Reset(source);
1719 while (buffer->has_more()) {
1720 uint16_t character = buffer->GetNext();
1721 if (character >= 256) {
1722 escaped_length += 6;
1723 } else if (IsNotEscaped(character)) {
1724 escaped_length++;
1725 } else {
1726 escaped_length += 3;
1727 }
1728 // We don't allow strings that are longer than Smi range.
1729 if (!Smi::IsValid(escaped_length)) {
1730 Top::context()->mark_out_of_memory();
1731 return Failure::OutOfMemoryException();
1732 }
1733 }
1734 }
1735 // No length change implies no change. Return original string if no change.
1736 if (escaped_length == length) {
1737 return source;
1738 }
1739 Object* o = Heap::AllocateRawAsciiString(escaped_length);
1740 if (o->IsFailure()) return o;
1741 String* destination = String::cast(o);
1742 int dest_position = 0;
1743
1744 Access<StringInputBuffer> buffer(&string_input_buffer);
1745 buffer->Rewind();
1746 while (buffer->has_more()) {
1747 uint16_t character = buffer->GetNext();
1748 if (character >= 256) {
1749 destination->Set(dest_position, '%');
1750 destination->Set(dest_position+1, 'u');
1751 destination->Set(dest_position+2, hex_chars[character >> 12]);
1752 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
1753 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
1754 destination->Set(dest_position+5, hex_chars[character & 0xf]);
1755 dest_position += 6;
1756 } else if (IsNotEscaped(character)) {
1757 destination->Set(dest_position, character);
1758 dest_position++;
1759 } else {
1760 destination->Set(dest_position, '%');
1761 destination->Set(dest_position+1, hex_chars[character >> 4]);
1762 destination->Set(dest_position+2, hex_chars[character & 0xf]);
1763 dest_position += 3;
1764 }
1765 }
1766 return destination;
1767}
1768
1769
1770static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
1771 static const signed char kHexValue['g'] = {
1772 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1773 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1774 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1775 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
1776 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1777 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1778 -1, 10, 11, 12, 13, 14, 15 };
1779
1780 if (character1 > 'f') return -1;
1781 int hi = kHexValue[character1];
1782 if (hi == -1) return -1;
1783 if (character2 > 'f') return -1;
1784 int lo = kHexValue[character2];
1785 if (lo == -1) return -1;
1786 return (hi << 4) + lo;
1787}
1788
1789
1790static inline int Unescape(String* source, int i, int length, int* step) {
1791 uint16_t character = source->Get(i);
1792 int32_t hi, lo;
1793 if (character == '%' &&
1794 i <= length - 6 &&
1795 source->Get(i + 1) == 'u' &&
1796 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
1797 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
1798 *step = 6;
1799 return (hi << 8) + lo;
1800 } else if (character == '%' &&
1801 i <= length - 3 &&
1802 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
1803 *step = 3;
1804 return lo;
1805 } else {
1806 *step = 1;
1807 return character;
1808 }
1809}
1810
1811
1812static Object* Runtime_URIUnescape(Arguments args) {
1813 NoHandleAllocation ha;
1814 ASSERT(args.length() == 1);
1815 CONVERT_CHECKED(String, source, args[0]);
1816
1817 source->TryFlatten();
1818
1819 bool ascii = true;
1820 int length = source->length();
1821
1822 int unescaped_length = 0;
1823 for (int i = 0; i < length; unescaped_length++) {
1824 int step;
1825 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
1826 ascii = false;
1827 i += step;
1828 }
1829
1830 // No length change implies no change. Return original string if no change.
1831 if (unescaped_length == length)
1832 return source;
1833
1834 Object* o = ascii ?
1835 Heap::AllocateRawAsciiString(unescaped_length) :
1836 Heap::AllocateRawTwoByteString(unescaped_length);
1837 if (o->IsFailure()) return o;
1838 String* destination = String::cast(o);
1839
1840 int dest_position = 0;
1841 for (int i = 0; i < length; dest_position++) {
1842 int step;
1843 destination->Set(dest_position, Unescape(source, i, length, &step));
1844 i += step;
1845 }
1846 return destination;
1847}
1848
1849
1850static Object* Runtime_StringParseInt(Arguments args) {
1851 NoHandleAllocation ha;
1852
1853 CONVERT_CHECKED(String, s, args[0]);
1854 CONVERT_DOUBLE_CHECKED(n, args[1]);
1855 int radix = FastD2I(n);
1856
1857 s->TryFlatten();
1858
1859 int len = s->length();
1860 int i;
1861
1862 // Skip leading white space.
1863 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
1864 if (i == len) return Heap::nan_value();
1865
1866 // Compute the sign (default to +).
1867 int sign = 1;
1868 if (s->Get(i) == '-') {
1869 sign = -1;
1870 i++;
1871 } else if (s->Get(i) == '+') {
1872 i++;
1873 }
1874
1875 // Compute the radix if 0.
1876 if (radix == 0) {
1877 radix = 10;
1878 if (i < len && s->Get(i) == '0') {
1879 radix = 8;
1880 if (i + 1 < len) {
1881 int c = s->Get(i + 1);
1882 if (c == 'x' || c == 'X') {
1883 radix = 16;
1884 i += 2;
1885 }
1886 }
1887 }
1888 } else if (radix == 16) {
1889 // Allow 0x or 0X prefix if radix is 16.
1890 if (i + 1 < len && s->Get(i) == '0') {
1891 int c = s->Get(i + 1);
1892 if (c == 'x' || c == 'X') i += 2;
1893 }
1894 }
1895
1896 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1897 double value;
1898 int end_index = StringToInt(s, i, radix, &value);
1899 if (end_index != i) {
1900 return Heap::NumberFromDouble(sign * value);
1901 }
1902 return Heap::nan_value();
1903}
1904
1905
1906static Object* Runtime_StringParseFloat(Arguments args) {
1907 NoHandleAllocation ha;
1908 CONVERT_CHECKED(String, str, args[0]);
1909
1910 // ECMA-262 section 15.1.2.3, empty string is NaN
1911 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
1912
1913 // Create a number object from the value.
1914 return Heap::NumberFromDouble(value);
1915}
1916
1917
1918static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
1919static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
1920
1921
1922template <class Converter>
1923static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926
1927 CONVERT_CHECKED(String, s, args[0]);
1928 int raw_string_length = s->length();
1929 // Assume that the string is not empty; we need this assumption later
1930 if (raw_string_length == 0) return s;
1931 int length = raw_string_length;
1932
1933 s->TryFlatten();
1934
1935 // We try this twice, once with the assumption that the result is
1936 // no longer than the input and, if that assumption breaks, again
1937 // with the exact length. This is implemented using a goto back
1938 // to this label if we discover that the assumption doesn't hold.
1939 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00001940 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 try_convert:
1942
1943 // Allocate the resulting string.
1944 //
1945 // NOTE: This assumes that the upper/lower case of an ascii
1946 // character is also ascii. This is currently the case, but it
1947 // might break in the future if we implement more context and locale
1948 // dependent upper/lower conversions.
1949 Object* o = s->IsAscii()
1950 ? Heap::AllocateRawAsciiString(length)
1951 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 String* result = String::cast(o);
1954 bool has_changed_character = false;
1955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 // Convert all characters to upper case, assuming that they will fit
1957 // in the buffer
1958 Access<StringInputBuffer> buffer(&string_input_buffer);
1959 buffer->Reset(s);
1960 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
1961 int i = 0;
1962 // We can assume that the string is not empty
1963 uc32 current = buffer->GetNext();
1964 while (i < length) {
1965 uc32 next = buffer->has_more() ? buffer->GetNext() : 0;
1966 int char_length = mapping->get(current, next, chars);
1967 if (char_length == 0) {
1968 // The case conversion of this character is the character itself.
1969 result->Set(i, current);
1970 i++;
1971 } else if (char_length == 1) {
1972 // Common case: converting the letter resulted in one character.
1973 ASSERT(static_cast<uc32>(chars[0]) != current);
1974 result->Set(i, chars[0]);
1975 has_changed_character = true;
1976 i++;
1977 } else if (length == raw_string_length) {
1978 // We've assumed that the result would be as long as the
1979 // input but here is a character that converts to several
1980 // characters. No matter, we calculate the exact length
1981 // of the result and try the whole thing again.
1982 //
1983 // Note that this leaves room for optimization. We could just
1984 // memcpy what we already have to the result string. Also,
1985 // the result string is the last object allocated we could
1986 // "realloc" it and probably, in the vast majority of cases,
1987 // extend the existing string to be able to hold the full
1988 // result.
1989 int current_length = i + char_length + mapping->get(next, 0, chars);
1990 while (buffer->has_more()) {
1991 current = buffer->GetNext();
1992 int char_length = mapping->get(current, 0, chars);
1993 if (char_length == 0) char_length = 1;
1994 current += char_length;
1995 }
1996 length = current_length;
1997 goto try_convert;
1998 } else {
1999 for (int j = 0; j < char_length; j++) {
2000 result->Set(i, chars[j]);
2001 i++;
2002 }
2003 has_changed_character = true;
2004 }
2005 current = next;
2006 }
2007 if (has_changed_character) {
2008 return result;
2009 } else {
2010 // If we didn't actually change anything in doing the conversion
2011 // we simple return the result and let the converted string
2012 // become garbage; there is no reason to keep two identical strings
2013 // alive.
2014 return s;
2015 }
2016}
2017
2018
2019static Object* Runtime_StringToLowerCase(Arguments args) {
2020 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2021}
2022
2023
2024static Object* Runtime_StringToUpperCase(Arguments args) {
2025 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2026}
2027
2028
2029static Object* Runtime_ConsStringFst(Arguments args) {
2030 NoHandleAllocation ha;
2031
2032 CONVERT_CHECKED(ConsString, str, args[0]);
2033 return str->first();
2034}
2035
2036
2037static Object* Runtime_ConsStringSnd(Arguments args) {
2038 NoHandleAllocation ha;
2039
2040 CONVERT_CHECKED(ConsString, str, args[0]);
2041 return str->second();
2042}
2043
2044
2045static Object* Runtime_NumberToString(Arguments args) {
2046 NoHandleAllocation ha;
2047 ASSERT(args.length() == 1);
2048
2049 Object* number = args[0];
2050 RUNTIME_ASSERT(number->IsNumber());
2051
2052 Object* cached = Heap::GetNumberStringCache(number);
2053 if (cached != Heap::undefined_value()) {
2054 return cached;
2055 }
2056
2057 char arr[100];
2058 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2059 const char* str;
2060 if (number->IsSmi()) {
2061 int num = Smi::cast(number)->value();
2062 str = IntToCString(num, buffer);
2063 } else {
2064 double num = HeapNumber::cast(number)->value();
2065 str = DoubleToCString(num, buffer);
2066 }
2067 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2068
2069 if (!result->IsFailure()) {
2070 Heap::SetNumberStringCache(number, String::cast(result));
2071 }
2072 return result;
2073}
2074
2075
2076static Object* Runtime_NumberToInteger(Arguments args) {
2077 NoHandleAllocation ha;
2078 ASSERT(args.length() == 1);
2079
2080 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002081 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002082 CONVERT_DOUBLE_CHECKED(number, obj);
2083 return Heap::NumberFromDouble(DoubleToInteger(number));
2084}
2085
2086
2087static Object* Runtime_NumberToJSUint32(Arguments args) {
2088 NoHandleAllocation ha;
2089 ASSERT(args.length() == 1);
2090
2091 Object* obj = args[0];
2092 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2093 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2094 return Heap::NumberFromUint32(number);
2095}
2096
2097
2098static Object* Runtime_NumberToJSInt32(Arguments args) {
2099 NoHandleAllocation ha;
2100 ASSERT(args.length() == 1);
2101
2102 Object* obj = args[0];
2103 if (obj->IsSmi()) return obj;
2104 CONVERT_DOUBLE_CHECKED(number, obj);
2105 return Heap::NumberFromInt32(DoubleToInt32(number));
2106}
2107
2108
2109static Object* Runtime_NumberAdd(Arguments args) {
2110 NoHandleAllocation ha;
2111 ASSERT(args.length() == 2);
2112
2113 CONVERT_DOUBLE_CHECKED(x, args[0]);
2114 CONVERT_DOUBLE_CHECKED(y, args[1]);
2115 return Heap::AllocateHeapNumber(x + y);
2116}
2117
2118
2119static Object* Runtime_NumberSub(Arguments args) {
2120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 2);
2122
2123 CONVERT_DOUBLE_CHECKED(x, args[0]);
2124 CONVERT_DOUBLE_CHECKED(y, args[1]);
2125 return Heap::AllocateHeapNumber(x - y);
2126}
2127
2128
2129static Object* Runtime_NumberMul(Arguments args) {
2130 NoHandleAllocation ha;
2131 ASSERT(args.length() == 2);
2132
2133 CONVERT_DOUBLE_CHECKED(x, args[0]);
2134 CONVERT_DOUBLE_CHECKED(y, args[1]);
2135 return Heap::AllocateHeapNumber(x * y);
2136}
2137
2138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002139static Object* Runtime_NumberUnaryMinus(Arguments args) {
2140 NoHandleAllocation ha;
2141 ASSERT(args.length() == 1);
2142
2143 CONVERT_DOUBLE_CHECKED(x, args[0]);
2144 return Heap::AllocateHeapNumber(-x);
2145}
2146
2147
2148static Object* Runtime_NumberDiv(Arguments args) {
2149 NoHandleAllocation ha;
2150 ASSERT(args.length() == 2);
2151
2152 CONVERT_DOUBLE_CHECKED(x, args[0]);
2153 CONVERT_DOUBLE_CHECKED(y, args[1]);
2154 return Heap::NewNumberFromDouble(x / y);
2155}
2156
2157
2158static Object* Runtime_NumberMod(Arguments args) {
2159 NoHandleAllocation ha;
2160 ASSERT(args.length() == 2);
2161
2162 CONVERT_DOUBLE_CHECKED(x, args[0]);
2163 CONVERT_DOUBLE_CHECKED(y, args[1]);
2164
2165#ifdef WIN32
2166 // Workaround MS fmod bugs. ECMA-262 says:
2167 // dividend is finite and divisor is an infinity => result equals dividend
2168 // dividend is a zero and divisor is nonzero finite => result equals dividend
2169 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2170 !(x == 0 && (y != 0 && isfinite(y))))
2171#endif
2172 x = fmod(x, y);
2173 // NewNumberFromDouble may return a Smi instead of a Number object
2174 return Heap::NewNumberFromDouble(x);
2175}
2176
2177
2178static Object* Runtime_StringAdd(Arguments args) {
2179 NoHandleAllocation ha;
2180 ASSERT(args.length() == 2);
2181
2182 CONVERT_CHECKED(String, str1, args[0]);
2183 CONVERT_CHECKED(String, str2, args[1]);
2184 int len1 = str1->length();
2185 int len2 = str2->length();
2186 if (len1 == 0) return str2;
2187 if (len2 == 0) return str1;
2188 int length_sum = len1 + len2;
2189 // Make sure that an out of memory exception is thrown if the length
2190 // of the new cons string is too large to fit in a Smi.
2191 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2192 Top::context()->mark_out_of_memory();
2193 return Failure::OutOfMemoryException();
2194 }
2195 return Heap::AllocateConsString(str1, str2);
2196}
2197
2198
2199static Object* Runtime_StringBuilderConcat(Arguments args) {
2200 NoHandleAllocation ha;
2201 ASSERT(args.length() == 2);
2202 CONVERT_CHECKED(JSArray, array, args[0]);
2203 CONVERT_CHECKED(String, special, args[1]);
2204 int special_length = special->length();
2205 Object* smi_array_length = array->length();
2206 if (!smi_array_length->IsSmi()) {
2207 Top::context()->mark_out_of_memory();
2208 return Failure::OutOfMemoryException();
2209 }
2210 int array_length = Smi::cast(smi_array_length)->value();
2211 if (!array->HasFastElements()) {
2212 return Top::Throw(Heap::illegal_argument_symbol());
2213 }
2214 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002215 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002218
2219 if (array_length == 0) {
2220 return Heap::empty_string();
2221 } else if (array_length == 1) {
2222 Object* first = fixed_array->get(0);
2223 if (first->IsString()) return first;
2224 }
2225
2226 bool ascii = special->IsAscii();
2227 int position = 0;
2228 for (int i = 0; i < array_length; i++) {
2229 Object* elt = fixed_array->get(i);
2230 if (elt->IsSmi()) {
2231 int len = Smi::cast(elt)->value();
2232 int pos = len >> 11;
2233 len &= 0x7ff;
2234 if (pos + len > special_length) {
2235 return Top::Throw(Heap::illegal_argument_symbol());
2236 }
2237 position += len;
2238 } else if (elt->IsString()) {
2239 String* element = String::cast(elt);
2240 int element_length = element->length();
2241 if (!Smi::IsValid(element_length + position)) {
2242 Top::context()->mark_out_of_memory();
2243 return Failure::OutOfMemoryException();
2244 }
2245 position += element_length;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002246 if (ascii && !element->IsAscii()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002249 } else {
2250 return Top::Throw(Heap::illegal_argument_symbol());
2251 }
2252 }
2253
2254 int length = position;
2255 position = 0;
2256 Object* object;
2257 if (ascii) {
2258 object = Heap::AllocateRawAsciiString(length);
2259 } else {
2260 object = Heap::AllocateRawTwoByteString(length);
2261 }
2262 if (object->IsFailure()) return object;
2263
2264 String* answer = String::cast(object);
2265 for (int i = 0; i < array_length; i++) {
2266 Object* element = fixed_array->get(i);
2267 if (element->IsSmi()) {
2268 int len = Smi::cast(element)->value();
2269 int pos = len >> 11;
2270 len &= 0x7ff;
2271 String::Flatten(special, answer, pos, pos + len, position);
2272 position += len;
2273 } else {
2274 String* string = String::cast(element);
2275 int element_length = string->length();
2276 String::Flatten(string, answer, 0, element_length, position);
2277 position += element_length;
2278 }
2279 }
2280 return answer;
2281}
2282
2283
2284static Object* Runtime_NumberOr(Arguments args) {
2285 NoHandleAllocation ha;
2286 ASSERT(args.length() == 2);
2287
2288 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2289 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2290 return Heap::NumberFromInt32(x | y);
2291}
2292
2293
2294static Object* Runtime_NumberAnd(Arguments args) {
2295 NoHandleAllocation ha;
2296 ASSERT(args.length() == 2);
2297
2298 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2299 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2300 return Heap::NumberFromInt32(x & y);
2301}
2302
2303
2304static Object* Runtime_NumberXor(Arguments args) {
2305 NoHandleAllocation ha;
2306 ASSERT(args.length() == 2);
2307
2308 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2309 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2310 return Heap::NumberFromInt32(x ^ y);
2311}
2312
2313
2314static Object* Runtime_NumberNot(Arguments args) {
2315 NoHandleAllocation ha;
2316 ASSERT(args.length() == 1);
2317
2318 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2319 return Heap::NumberFromInt32(~x);
2320}
2321
2322
2323static Object* Runtime_NumberShl(Arguments args) {
2324 NoHandleAllocation ha;
2325 ASSERT(args.length() == 2);
2326
2327 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2328 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2329 return Heap::NumberFromInt32(x << (y & 0x1f));
2330}
2331
2332
2333static Object* Runtime_NumberShr(Arguments args) {
2334 NoHandleAllocation ha;
2335 ASSERT(args.length() == 2);
2336
2337 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2338 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2339 return Heap::NumberFromUint32(x >> (y & 0x1f));
2340}
2341
2342
2343static Object* Runtime_NumberSar(Arguments args) {
2344 NoHandleAllocation ha;
2345 ASSERT(args.length() == 2);
2346
2347 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2348 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2349 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2350}
2351
2352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002353static Object* Runtime_NumberEquals(Arguments args) {
2354 NoHandleAllocation ha;
2355 ASSERT(args.length() == 2);
2356
2357 CONVERT_DOUBLE_CHECKED(x, args[0]);
2358 CONVERT_DOUBLE_CHECKED(y, args[1]);
2359 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2360 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2361 if (x == y) return Smi::FromInt(EQUAL);
2362 Object* result;
2363 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2364 result = Smi::FromInt(EQUAL);
2365 } else {
2366 result = Smi::FromInt(NOT_EQUAL);
2367 }
2368 return result;
2369}
2370
2371
2372static Object* Runtime_StringEquals(Arguments args) {
2373 NoHandleAllocation ha;
2374 ASSERT(args.length() == 2);
2375
2376 CONVERT_CHECKED(String, x, args[0]);
2377 CONVERT_CHECKED(String, y, args[1]);
2378
2379 // This is very similar to String::Equals(String*) but that version
2380 // requires flattened strings as input, whereas we flatten the
2381 // strings only if the fast cases fail. Note that this may fail,
2382 // requiring a GC. String::Equals(String*) returns a bool and has
2383 // no way to signal a failure.
2384 if (y == x) return Smi::FromInt(EQUAL);
2385 if (x->IsSymbol() && y->IsSymbol()) return Smi::FromInt(NOT_EQUAL);
2386 // Compare contents
2387 int len = x->length();
2388 if (len != y->length()) return Smi::FromInt(NOT_EQUAL);
2389 if (len == 0) return Smi::FromInt(EQUAL);
2390 // Fast case: First, middle and last characters.
2391 if (x->Get(0) != y->Get(0)) return Smi::FromInt(NOT_EQUAL);
2392 if (x->Get(len>>1) != y->Get(len>>1)) return Smi::FromInt(NOT_EQUAL);
2393 if (x->Get(len - 1) != y->Get(len - 1)) return Smi::FromInt(NOT_EQUAL);
2394
2395 x->TryFlatten();
2396 y->TryFlatten();
2397
2398 static StringInputBuffer buf1;
2399 static StringInputBuffer buf2;
2400 buf1.Reset(x);
2401 buf2.Reset(y);
2402 while (buf1.has_more()) {
2403 if (buf1.GetNext() != buf2.GetNext())
2404 return Smi::FromInt(NOT_EQUAL);
2405 }
2406 return Smi::FromInt(EQUAL);
2407}
2408
2409
2410static Object* Runtime_NumberCompare(Arguments args) {
2411 NoHandleAllocation ha;
2412 ASSERT(args.length() == 3);
2413
2414 CONVERT_DOUBLE_CHECKED(x, args[0]);
2415 CONVERT_DOUBLE_CHECKED(y, args[1]);
2416 if (isnan(x) || isnan(y)) return args[2];
2417 if (x == y) return Smi::FromInt(EQUAL);
2418 if (isless(x, y)) return Smi::FromInt(LESS);
2419 return Smi::FromInt(GREATER);
2420}
2421
2422
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002423// Compare two Smis as if they were converted to strings and then
2424// compared lexicographically.
2425static Object* Runtime_SmiLexicographicCompare(Arguments args) {
2426 NoHandleAllocation ha;
2427 ASSERT(args.length() == 2);
2428
2429 // Arrays for the individual characters of the two Smis. Smis are
2430 // 31 bit integers and 10 decimal digits are therefore enough.
2431 static int x_elms[10];
2432 static int y_elms[10];
2433
2434 // Extract the integer values from the Smis.
2435 CONVERT_CHECKED(Smi, x, args[0]);
2436 CONVERT_CHECKED(Smi, y, args[1]);
2437 int x_value = x->value();
2438 int y_value = y->value();
2439
2440 // If the integers are equal so are the string representations.
2441 if (x_value == y_value) return Smi::FromInt(EQUAL);
2442
2443 // If one of the integers are zero the normal integer order is the
2444 // same as the lexicographic order of the string representations.
2445 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
2446
2447 // If only one of the intergers is negative the negative number is
2448 // smallest because the char code of '-' is less than the char code
2449 // of any digit. Otherwise, we make both values positive.
2450 if (x_value < 0 || y_value < 0) {
2451 if (y_value >= 0) return Smi::FromInt(LESS);
2452 if (x_value >= 0) return Smi::FromInt(GREATER);
2453 x_value = -x_value;
2454 y_value = -y_value;
2455 }
2456
2457 // Convert the integers to arrays of their decimal digits.
2458 int x_index = 0;
2459 int y_index = 0;
2460 while (x_value > 0) {
2461 x_elms[x_index++] = x_value % 10;
2462 x_value /= 10;
2463 }
2464 while (y_value > 0) {
2465 y_elms[y_index++] = y_value % 10;
2466 y_value /= 10;
2467 }
2468
2469 // Loop through the arrays of decimal digits finding the first place
2470 // where they differ.
2471 while (--x_index >= 0 && --y_index >= 0) {
2472 int diff = x_elms[x_index] - y_elms[y_index];
2473 if (diff != 0) return Smi::FromInt(diff);
2474 }
2475
2476 // If one array is a suffix of the other array, the longest array is
2477 // the representation of the largest of the Smis in the
2478 // lexicographic ordering.
2479 return Smi::FromInt(x_index - y_index);
2480}
2481
2482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483static Object* Runtime_StringCompare(Arguments args) {
2484 NoHandleAllocation ha;
2485 ASSERT(args.length() == 2);
2486
2487 CONVERT_CHECKED(String, x, args[0]);
2488 CONVERT_CHECKED(String, y, args[1]);
2489
2490 // A few fast case tests before we flatten.
2491 if (x == y) return Smi::FromInt(EQUAL);
2492 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002493 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494 return Smi::FromInt(GREATER);
2495 } else if (x->length() == 0) {
2496 return Smi::FromInt(LESS);
2497 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002498
2499 int d = x->Get(0) - y->Get(0);
2500 if (d < 0) return Smi::FromInt(LESS);
2501 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002502
2503 x->TryFlatten();
2504 y->TryFlatten();
2505
2506 static StringInputBuffer bufx;
2507 static StringInputBuffer bufy;
2508 bufx.Reset(x);
2509 bufy.Reset(y);
2510 while (bufx.has_more() && bufy.has_more()) {
2511 int d = bufx.GetNext() - bufy.GetNext();
2512 if (d < 0) return Smi::FromInt(LESS);
2513 else if (d > 0) return Smi::FromInt(GREATER);
2514 }
2515
2516 // x is (non-trivial) prefix of y:
2517 if (bufy.has_more()) return Smi::FromInt(LESS);
2518 // y is prefix of x:
2519 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2520}
2521
2522
2523static Object* Runtime_Math_abs(Arguments args) {
2524 NoHandleAllocation ha;
2525 ASSERT(args.length() == 1);
2526
2527 CONVERT_DOUBLE_CHECKED(x, args[0]);
2528 return Heap::AllocateHeapNumber(fabs(x));
2529}
2530
2531
2532static Object* Runtime_Math_acos(Arguments args) {
2533 NoHandleAllocation ha;
2534 ASSERT(args.length() == 1);
2535
2536 CONVERT_DOUBLE_CHECKED(x, args[0]);
2537 return Heap::AllocateHeapNumber(acos(x));
2538}
2539
2540
2541static Object* Runtime_Math_asin(Arguments args) {
2542 NoHandleAllocation ha;
2543 ASSERT(args.length() == 1);
2544
2545 CONVERT_DOUBLE_CHECKED(x, args[0]);
2546 return Heap::AllocateHeapNumber(asin(x));
2547}
2548
2549
2550static Object* Runtime_Math_atan(Arguments args) {
2551 NoHandleAllocation ha;
2552 ASSERT(args.length() == 1);
2553
2554 CONVERT_DOUBLE_CHECKED(x, args[0]);
2555 return Heap::AllocateHeapNumber(atan(x));
2556}
2557
2558
2559static Object* Runtime_Math_atan2(Arguments args) {
2560 NoHandleAllocation ha;
2561 ASSERT(args.length() == 2);
2562
2563 CONVERT_DOUBLE_CHECKED(x, args[0]);
2564 CONVERT_DOUBLE_CHECKED(y, args[1]);
2565 double result;
2566 if (isinf(x) && isinf(y)) {
2567 // Make sure that the result in case of two infinite arguments
2568 // is a multiple of Pi / 4. The sign of the result is determined
2569 // by the first argument (x) and the sign of the second argument
2570 // determines the multiplier: one or three.
2571 static double kPiDividedBy4 = 0.78539816339744830962;
2572 int multiplier = (x < 0) ? -1 : 1;
2573 if (y < 0) multiplier *= 3;
2574 result = multiplier * kPiDividedBy4;
2575 } else {
2576 result = atan2(x, y);
2577 }
2578 return Heap::AllocateHeapNumber(result);
2579}
2580
2581
2582static Object* Runtime_Math_ceil(Arguments args) {
2583 NoHandleAllocation ha;
2584 ASSERT(args.length() == 1);
2585
2586 CONVERT_DOUBLE_CHECKED(x, args[0]);
2587 return Heap::NumberFromDouble(ceiling(x));
2588}
2589
2590
2591static Object* Runtime_Math_cos(Arguments args) {
2592 NoHandleAllocation ha;
2593 ASSERT(args.length() == 1);
2594
2595 CONVERT_DOUBLE_CHECKED(x, args[0]);
2596 return Heap::AllocateHeapNumber(cos(x));
2597}
2598
2599
2600static Object* Runtime_Math_exp(Arguments args) {
2601 NoHandleAllocation ha;
2602 ASSERT(args.length() == 1);
2603
2604 CONVERT_DOUBLE_CHECKED(x, args[0]);
2605 return Heap::AllocateHeapNumber(exp(x));
2606}
2607
2608
2609static Object* Runtime_Math_floor(Arguments args) {
2610 NoHandleAllocation ha;
2611 ASSERT(args.length() == 1);
2612
2613 CONVERT_DOUBLE_CHECKED(x, args[0]);
2614 return Heap::NumberFromDouble(floor(x));
2615}
2616
2617
2618static Object* Runtime_Math_log(Arguments args) {
2619 NoHandleAllocation ha;
2620 ASSERT(args.length() == 1);
2621
2622 CONVERT_DOUBLE_CHECKED(x, args[0]);
2623 return Heap::AllocateHeapNumber(log(x));
2624}
2625
2626
2627static Object* Runtime_Math_pow(Arguments args) {
2628 NoHandleAllocation ha;
2629 ASSERT(args.length() == 2);
2630
2631 CONVERT_DOUBLE_CHECKED(x, args[0]);
2632 CONVERT_DOUBLE_CHECKED(y, args[1]);
2633 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
2634 return Heap::nan_value();
2635 } else if (y == 0) {
2636 return Smi::FromInt(1);
2637 } else {
2638 return Heap::AllocateHeapNumber(pow(x, y));
2639 }
2640}
2641
2642// Returns a number value with positive sign, greater than or equal to
2643// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00002644static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00002646 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002647
2648 // To get much better precision, we combine the results of two
2649 // invocations of random(). The result is computed by normalizing a
2650 // double in the range [0, RAND_MAX + 1) obtained by adding the
2651 // high-order bits in the range [0, RAND_MAX] with the low-order
2652 // bits in the range [0, 1).
2653 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
2654 double hi = static_cast<double>(random());
2655 double result = (hi + lo) / (RAND_MAX + 1.0);
2656 ASSERT(result >= 0 && result < 1);
2657 return Heap::AllocateHeapNumber(result);
2658}
2659
2660
2661static Object* Runtime_Math_round(Arguments args) {
2662 NoHandleAllocation ha;
2663 ASSERT(args.length() == 1);
2664
2665 CONVERT_DOUBLE_CHECKED(x, args[0]);
2666 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
2667 return Heap::NumberFromDouble(floor(x + 0.5));
2668}
2669
2670
2671static Object* Runtime_Math_sin(Arguments args) {
2672 NoHandleAllocation ha;
2673 ASSERT(args.length() == 1);
2674
2675 CONVERT_DOUBLE_CHECKED(x, args[0]);
2676 return Heap::AllocateHeapNumber(sin(x));
2677}
2678
2679
2680static Object* Runtime_Math_sqrt(Arguments args) {
2681 NoHandleAllocation ha;
2682 ASSERT(args.length() == 1);
2683
2684 CONVERT_DOUBLE_CHECKED(x, args[0]);
2685 return Heap::AllocateHeapNumber(sqrt(x));
2686}
2687
2688
2689static Object* Runtime_Math_tan(Arguments args) {
2690 NoHandleAllocation ha;
2691 ASSERT(args.length() == 1);
2692
2693 CONVERT_DOUBLE_CHECKED(x, args[0]);
2694 return Heap::AllocateHeapNumber(tan(x));
2695}
2696
2697
2698static Object* Runtime_NewArguments(Arguments args) {
2699 NoHandleAllocation ha;
2700 ASSERT(args.length() == 1);
2701
2702 // ECMA-262, 3rd., 10.1.8, p.39
2703 CONVERT_CHECKED(JSFunction, callee, args[0]);
2704
2705 // Compute the frame holding the arguments.
2706 JavaScriptFrameIterator it;
2707 it.AdvanceToArgumentsFrame();
2708 JavaScriptFrame* frame = it.frame();
2709
2710 const int length = frame->GetProvidedParametersCount();
2711 Object* result = Heap::AllocateArgumentsObject(callee, length);
2712 if (result->IsFailure()) return result;
2713 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
2714 ASSERT(array->length() == length);
2715 for (int i = 0; i < length; i++) {
2716 array->set(i, frame->GetParameter(i));
2717 }
2718 return result;
2719}
2720
2721
2722static Object* Runtime_NewClosure(Arguments args) {
2723 HandleScope scope;
2724 ASSERT(args.length() == 2);
2725 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
2726 CONVERT_ARG_CHECKED(Context, context, 1);
2727
2728 Handle<JSFunction> result =
2729 Factory::NewFunctionFromBoilerplate(boilerplate, context);
2730 return *result;
2731}
2732
2733
2734static Object* Runtime_NewObject(Arguments args) {
2735 NoHandleAllocation ha;
2736 ASSERT(args.length() == 1);
2737
2738 Object* constructor = args[0];
2739 if (constructor->IsJSFunction()) {
2740 JSFunction* function = JSFunction::cast(constructor);
2741
2742 // Handle steping into constructors.
2743 if (Debug::StepInActive()) {
2744 StackFrameIterator it;
2745 it.Advance();
2746 ASSERT(InternalFrame::cast(it.frame())->is_construct_trampoline());
2747 it.Advance();
2748 if (it.frame()->fp() == Debug::step_in_fp()) {
2749 HandleScope scope;
2750 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
2751 }
2752 }
2753
2754 if (function->has_initial_map() &&
2755 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
2756 // The 'Function' function ignores the receiver object when
2757 // called using 'new' and creates a new JSFunction object that
2758 // is returned. The receiver object is only used for error
2759 // reporting if an error occurs when constructing the new
2760 // JSFunction. AllocateJSObject should not be used to allocate
2761 // JSFunctions since it does not properly initialize the shared
2762 // part of the function. Since the receiver is ignored anyway,
2763 // we use the global object as the receiver instead of a new
2764 // JSFunction object. This way, errors are reported the same
2765 // way whether or not 'Function' is called using 'new'.
2766 return Top::context()->global();
2767 }
2768 return Heap::AllocateJSObject(function);
2769 }
2770
2771 HandleScope scope;
2772 Handle<Object> cons(constructor);
2773 // The constructor is not a function; throw a type error.
2774 Handle<Object> type_error =
2775 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
2776 return Top::Throw(*type_error);
2777}
2778
2779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780static Object* Runtime_LazyCompile(Arguments args) {
2781 HandleScope scope;
2782 ASSERT(args.length() == 1);
2783
2784 Handle<JSFunction> function = args.at<JSFunction>(0);
2785#ifdef DEBUG
2786 if (FLAG_trace_lazy) {
2787 PrintF("[lazy: ");
2788 function->shared()->name()->Print();
2789 PrintF("]\n");
2790 }
2791#endif
2792
2793 // Compile the target function.
2794 ASSERT(!function->is_compiled());
2795 if (!CompileLazy(function, KEEP_EXCEPTION)) {
2796 return Failure::Exception();
2797 }
2798
2799 return function->code();
2800}
2801
2802
2803static Object* Runtime_GetCalledFunction(Arguments args) {
2804 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00002805 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806 StackFrameIterator it;
2807 // Get past the JS-to-C exit frame.
2808 ASSERT(it.frame()->is_exit());
2809 it.Advance();
2810 // Get past the CALL_NON_FUNCTION activation frame.
2811 ASSERT(it.frame()->is_java_script());
2812 it.Advance();
2813 // Argument adaptor frames do not copy the function; we have to skip
2814 // past them to get to the real calling frame.
2815 if (it.frame()->is_arguments_adaptor()) it.Advance();
2816 // Get the function from the top of the expression stack of the
2817 // calling frame.
2818 StandardFrame* frame = StandardFrame::cast(it.frame());
2819 int index = frame->ComputeExpressionsCount() - 1;
2820 Object* result = frame->GetExpression(index);
2821 return result;
2822}
2823
2824
2825static Object* Runtime_GetFunctionDelegate(Arguments args) {
2826 HandleScope scope;
2827 ASSERT(args.length() == 1);
2828 RUNTIME_ASSERT(!args[0]->IsJSFunction());
2829 return *Execution::GetFunctionDelegate(args.at<Object>(0));
2830}
2831
2832
2833static Object* Runtime_NewContext(Arguments args) {
2834 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002835 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836
kasper.lund7276f142008-07-30 08:49:36 +00002837 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
2839 Object* result = Heap::AllocateFunctionContext(length, function);
2840 if (result->IsFailure()) return result;
2841
2842 Top::set_context(Context::cast(result));
2843
kasper.lund7276f142008-07-30 08:49:36 +00002844 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002845}
2846
2847
2848static Object* Runtime_PushContext(Arguments args) {
2849 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002850 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002851
2852 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00002853 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002854 if (!object->IsJSObject()) {
2855 object = object->ToObject();
2856 if (object->IsFailure()) {
2857 if (!Failure::cast(object)->IsInternalError()) return object;
2858 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00002859 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860 Handle<Object> result =
2861 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
2862 return Top::Throw(*result);
2863 }
2864 }
2865
2866 Object* result =
2867 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
2868 if (result->IsFailure()) return result;
2869
2870 Top::set_context(Context::cast(result));
2871
kasper.lund7276f142008-07-30 08:49:36 +00002872 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873}
2874
2875
2876static Object* Runtime_LookupContext(Arguments args) {
2877 HandleScope scope;
2878 ASSERT(args.length() == 2);
2879
2880 CONVERT_ARG_CHECKED(Context, context, 0);
2881 CONVERT_ARG_CHECKED(String, name, 1);
2882
2883 int index;
2884 PropertyAttributes attributes;
2885 ContextLookupFlags flags = FOLLOW_CHAINS;
2886 Handle<Object> context_obj =
2887 context->Lookup(name, flags, &index, &attributes);
2888
2889 if (index < 0 && *context_obj != NULL) {
2890 ASSERT(context_obj->IsJSObject());
2891 return *context_obj;
2892 }
2893
2894 // No intermediate context found. Use global object by default.
2895 return Top::context()->global();
2896}
2897
2898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899// A mechanism to return pairs of Object*'s. This is somewhat
2900// compiler-dependent as it assumes that a 64-bit value (a long long)
2901// is returned via two registers (edx:eax on ia32). Both the ia32 and
2902// arm platform support this; it is mostly an issue of "coaxing" the
2903// compiler to do the right thing.
2904//
2905// TODO(1236026): This is a non-portable hack that should be removed.
2906typedef uint64_t ObjPair;
2907ObjPair MakePair(Object* x, Object* y) {
2908 return reinterpret_cast<uint32_t>(x) |
2909 (reinterpret_cast<ObjPair>(y) << 32);
2910}
2911
2912
2913static Object* Unhole(Object* x, PropertyAttributes attributes) {
2914 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
2915 USE(attributes);
2916 return x->IsTheHole() ? Heap::undefined_value() : x;
2917}
2918
2919
2920static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
2921 HandleScope scope;
2922 ASSERT(args.length() == 2);
2923
2924 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
2925 Handle<Context> context = args.at<Context>(0);
2926 Handle<String> name(String::cast(args[1]));
2927
2928 int index;
2929 PropertyAttributes attributes;
2930 ContextLookupFlags flags = FOLLOW_CHAINS;
2931 Handle<Object> context_obj =
2932 context->Lookup(name, flags, &index, &attributes);
2933
2934 if (index >= 0) {
2935 if (context_obj->IsContext()) {
2936 // The context is an Execution context, and the "property" we were looking
2937 // for is a local variable in that context. According to ECMA-262, 3rd.,
2938 // 10.1.6 and 10.2.3, the receiver is the global object.
2939 return MakePair(
2940 Unhole(Handle<Context>::cast(context_obj)->get(index), attributes),
2941 Top::context()->global());
2942 } else {
2943 return MakePair(
2944 Unhole(Handle<JSObject>::cast(context_obj)->GetElement(index),
2945 attributes),
2946 *context_obj);
2947 }
2948 }
2949
2950 if (*context_obj != NULL) {
2951 ASSERT(Handle<JSObject>::cast(context_obj)->HasProperty(*name));
2952 // Note: As of 5/29/2008, GetProperty does the "unholing" and so this call
2953 // here is redundant. We left it anyway, to be explicit; also it's not clear
2954 // why GetProperty should do the unholing in the first place.
2955 return MakePair(
2956 Unhole(Handle<JSObject>::cast(context_obj)->GetProperty(*name),
2957 attributes),
2958 *context_obj);
2959 }
2960
2961 if (throw_error) {
2962 // The property doesn't exist - throw exception.
2963 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002964 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002965 return MakePair(Top::Throw(*reference_error), NULL);
2966 } else {
2967 // The property doesn't exist - return undefined
2968 return MakePair(Heap::undefined_value(), Heap::undefined_value());
2969 }
2970}
2971
2972
2973static ObjPair Runtime_LoadContextSlot(Arguments args) {
2974 return LoadContextSlotHelper(args, true);
2975}
2976
2977
2978static ObjPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
2979 return LoadContextSlotHelper(args, false);
2980}
2981
2982
2983static Object* Runtime_StoreContextSlot(Arguments args) {
2984 HandleScope scope;
2985 ASSERT(args.length() == 3);
2986
2987 Handle<Object> value(args[0]);
2988 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002989 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002990
2991 int index;
2992 PropertyAttributes attributes;
2993 ContextLookupFlags flags = FOLLOW_CHAINS;
2994 Handle<Object> context_obj =
2995 context->Lookup(name, flags, &index, &attributes);
2996
2997 if (index >= 0) {
2998 if (context_obj->IsContext()) {
2999 // Ignore if read_only variable.
3000 if ((attributes & READ_ONLY) == 0) {
3001 Handle<Context>::cast(context_obj)->set(index, *value);
3002 }
3003 } else {
3004 ASSERT((attributes & READ_ONLY) == 0);
3005 Object* result =
3006 Handle<JSObject>::cast(context_obj)->SetElement(index, *value);
3007 USE(result);
3008 ASSERT(!result->IsFailure());
3009 }
3010 return *value;
3011 }
3012
3013 // Slow case: The property is not in a FixedArray context.
3014 // It is either in an JSObject extension context or it was not found.
3015 Handle<JSObject> context_ext;
3016
3017 if (*context_obj != NULL) {
3018 // The property exists in the extension context.
3019 context_ext = Handle<JSObject>::cast(context_obj);
3020 } else {
3021 // The property was not found. It needs to be stored in the global context.
3022 ASSERT(attributes == ABSENT);
3023 attributes = NONE;
3024 context_ext = Handle<JSObject>(Top::context()->global());
3025 }
3026
3027 // Set the property, but ignore if read_only variable.
3028 if ((attributes & READ_ONLY) == 0) {
3029 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3030 if (set.is_null()) {
3031 // Failure::Exception is converted to a null handle in the
3032 // handle-based methods such as SetProperty. We therefore need
3033 // to convert null handles back to exceptions.
3034 ASSERT(Top::has_pending_exception());
3035 return Failure::Exception();
3036 }
3037 }
3038 return *value;
3039}
3040
3041
3042static Object* Runtime_Throw(Arguments args) {
3043 HandleScope scope;
3044 ASSERT(args.length() == 1);
3045
3046 return Top::Throw(args[0]);
3047}
3048
3049
3050static Object* Runtime_ReThrow(Arguments args) {
3051 HandleScope scope;
3052 ASSERT(args.length() == 1);
3053
3054 return Top::ReThrow(args[0]);
3055}
3056
3057
3058static Object* Runtime_ThrowReferenceError(Arguments args) {
3059 HandleScope scope;
3060 ASSERT(args.length() == 1);
3061
3062 Handle<Object> name(args[0]);
3063 Handle<Object> reference_error =
3064 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3065 return Top::Throw(*reference_error);
3066}
3067
3068
3069static Object* Runtime_StackOverflow(Arguments args) {
3070 NoHandleAllocation na;
3071 return Top::StackOverflow();
3072}
3073
3074
3075static Object* RuntimePreempt(Arguments args) {
3076 // Clear the preempt request flag.
3077 StackGuard::Continue(PREEMPT);
3078
3079 ContextSwitcher::PreemptionReceived();
3080
3081 {
3082 v8::Unlocker unlocker;
3083 Thread::YieldCPU();
3084 }
3085
3086 return Heap::undefined_value();
3087}
3088
3089
3090static Object* Runtime_DebugBreak(Arguments args) {
kasper.lund44510672008-07-25 07:37:58 +00003091 // Just continue if breaks are disabled or if we fail to load the debugger.
3092 if (Debug::disable_break() || !Debug::Load()) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003093 return args[0];
3094 }
3095
kasper.lund7276f142008-07-30 08:49:36 +00003096 // Don't break in system functions. If the current function is
3097 // either in the builtins object of some context or is in the debug
3098 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099 JavaScriptFrameIterator it;
3100 JavaScriptFrame* frame = it.frame();
3101 Object* fun = frame->function();
3102 if (fun->IsJSFunction()) {
3103 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3104 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
3105 return args[0];
3106 }
3107 }
3108
3109 // Clear the debug request flag.
3110 StackGuard::Continue(DEBUGBREAK);
3111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003112 HandleScope scope;
3113 SaveBreakFrame save;
3114 EnterDebuggerContext enter;
3115
kasper.lund7276f142008-07-30 08:49:36 +00003116 // Notify the debug event listeners.
3117 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118
3119 // Return to continue execution.
3120 return args[0];
3121}
3122
3123
3124static Object* Runtime_StackGuard(Arguments args) {
3125 ASSERT(args.length() == 1);
3126
3127 // First check if this is a real stack overflow.
3128 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3129
3130 // If not real stack overflow the stack guard was used to interrupt
3131 // execution for another purpose.
3132 if (StackGuard::IsDebugBreak()) Runtime_DebugBreak(args);
3133 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3134 if (StackGuard::IsInterrupted()) {
3135 // interrupt
3136 StackGuard::Continue(INTERRUPT);
3137 return Top::StackOverflow();
3138 }
3139 return Heap::undefined_value();
3140}
3141
3142
3143// NOTE: These PrintXXX functions are defined for all builds (not just
3144// DEBUG builds) because we may want to be able to trace function
3145// calls in all modes.
3146static void PrintString(String* str) {
3147 // not uncommon to have empty strings
3148 if (str->length() > 0) {
3149 SmartPointer<char> s =
3150 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3151 PrintF("%s", *s);
3152 }
3153}
3154
3155
3156static void PrintObject(Object* obj) {
3157 if (obj->IsSmi()) {
3158 PrintF("%d", Smi::cast(obj)->value());
3159 } else if (obj->IsString() || obj->IsSymbol()) {
3160 PrintString(String::cast(obj));
3161 } else if (obj->IsNumber()) {
3162 PrintF("%g", obj->Number());
3163 } else if (obj->IsFailure()) {
3164 PrintF("<failure>");
3165 } else if (obj->IsUndefined()) {
3166 PrintF("<undefined>");
3167 } else if (obj->IsNull()) {
3168 PrintF("<null>");
3169 } else if (obj->IsTrue()) {
3170 PrintF("<true>");
3171 } else if (obj->IsFalse()) {
3172 PrintF("<false>");
3173 } else {
3174 PrintF("%p", obj);
3175 }
3176}
3177
3178
3179static int StackSize() {
3180 int n = 0;
3181 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3182 return n;
3183}
3184
3185
3186static void PrintTransition(Object* result) {
3187 // indentation
3188 { const int nmax = 80;
3189 int n = StackSize();
3190 if (n <= nmax)
3191 PrintF("%4d:%*s", n, n, "");
3192 else
3193 PrintF("%4d:%*s", n, nmax, "...");
3194 }
3195
3196 if (result == NULL) {
3197 // constructor calls
3198 JavaScriptFrameIterator it;
3199 JavaScriptFrame* frame = it.frame();
3200 if (frame->IsConstructor()) PrintF("new ");
3201 // function name
3202 Object* fun = frame->function();
3203 if (fun->IsJSFunction()) {
3204 PrintObject(JSFunction::cast(fun)->shared()->name());
3205 } else {
3206 PrintObject(fun);
3207 }
3208 // function arguments
3209 // (we are intentionally only printing the actually
3210 // supplied parameters, not all parameters required)
3211 PrintF("(this=");
3212 PrintObject(frame->receiver());
3213 const int length = frame->GetProvidedParametersCount();
3214 for (int i = 0; i < length; i++) {
3215 PrintF(", ");
3216 PrintObject(frame->GetParameter(i));
3217 }
3218 PrintF(") {\n");
3219
3220 } else {
3221 // function result
3222 PrintF("} -> ");
3223 PrintObject(result);
3224 PrintF("\n");
3225 }
3226}
3227
3228
3229static Object* Runtime_TraceEnter(Arguments args) {
3230 NoHandleAllocation ha;
3231 PrintTransition(NULL);
3232 return args[0]; // return TOS
3233}
3234
3235
3236static Object* Runtime_TraceExit(Arguments args) {
3237 NoHandleAllocation ha;
3238 PrintTransition(args[0]);
3239 return args[0]; // return TOS
3240}
3241
3242
3243static Object* Runtime_DebugPrint(Arguments args) {
3244 NoHandleAllocation ha;
3245 ASSERT(args.length() == 1);
3246
3247#ifdef DEBUG
3248 if (args[0]->IsString()) {
3249 // If we have a string, assume it's a code "marker"
3250 // and print some interesting cpu debugging info.
3251 JavaScriptFrameIterator it;
3252 JavaScriptFrame* frame = it.frame();
3253 PrintF("fp = %p, sp = %p, pp = %p: ",
3254 frame->fp(), frame->sp(), frame->pp());
3255 } else {
3256 PrintF("DebugPrint: ");
3257 }
3258 args[0]->Print();
3259#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003260 // ShortPrint is available in release mode. Print is not.
3261 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262#endif
3263 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003264 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003265
3266 return args[0]; // return TOS
3267}
3268
3269
3270static Object* Runtime_DebugTrace(Arguments args) {
3271 ASSERT(args.length() == 1);
3272 NoHandleAllocation ha;
3273 Top::PrintStack();
3274 return args[0]; // return TOS
3275}
3276
3277
mads.s.ager31e71382008-08-13 09:32:07 +00003278static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003279 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003280 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003281
3282 // According to ECMA-262, section 15.9.1, page 117, the precision of
3283 // the number in a Date object representing a particular instant in
3284 // time is milliseconds. Therefore, we floor the result of getting
3285 // the OS time.
3286 double millis = floor(OS::TimeCurrentMillis());
3287 return Heap::NumberFromDouble(millis);
3288}
3289
3290
3291static Object* Runtime_DateParseString(Arguments args) {
3292 HandleScope scope;
3293 ASSERT(args.length() == 1);
3294
3295 CONVERT_CHECKED(String, string_object, args[0]);
3296
3297 Handle<String> str(string_object);
3298 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3299 if (DateParser::Parse(*str, *output)) {
3300 return *Factory::NewJSArrayWithElements(output);
3301 } else {
3302 return *Factory::null_value();
3303 }
3304}
3305
3306
3307static Object* Runtime_DateLocalTimezone(Arguments args) {
3308 NoHandleAllocation ha;
3309 ASSERT(args.length() == 1);
3310
3311 CONVERT_DOUBLE_CHECKED(x, args[0]);
3312 char* zone = OS::LocalTimezone(x);
3313 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3314}
3315
3316
3317static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3318 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003319 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003320
3321 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3322}
3323
3324
3325static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3326 NoHandleAllocation ha;
3327 ASSERT(args.length() == 1);
3328
3329 CONVERT_DOUBLE_CHECKED(x, args[0]);
3330 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3331}
3332
3333
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003334static Object* Runtime_NumberIsFinite(Arguments args) {
3335 NoHandleAllocation ha;
3336 ASSERT(args.length() == 1);
3337
3338 CONVERT_DOUBLE_CHECKED(value, args[0]);
3339 Object* result;
3340 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3341 result = Heap::false_value();
3342 } else {
3343 result = Heap::true_value();
3344 }
3345 return result;
3346}
3347
3348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349static Object* EvalContext() {
3350 // The topmost JS frame belongs to the eval function which called
3351 // the CompileString runtime function. We need to unwind one level
3352 // to get to the caller of eval.
3353 StackFrameLocator locator;
3354 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3355
kasper.lund44510672008-07-25 07:37:58 +00003356 // TODO(900055): Right now we check if the caller of eval() supports
3357 // eval to determine if it's an aliased eval or not. This may not be
3358 // entirely correct in the unlikely case where a function uses both
3359 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003360 HandleScope scope;
3361 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003362 // Aliased eval: Evaluate in the global context of the eval
3363 // function to support aliased, cross environment evals.
3364 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003365 }
3366
3367 // Fetch the caller context from the frame.
3368 Handle<Context> caller(Context::cast(frame->context()));
3369
3370 // Check for eval() invocations that cross environments. Use the
3371 // context from the stack if evaluating in current environment.
3372 Handle<Context> target = Top::global_context();
3373 if (caller->global_context() == *target) return *caller;
3374
3375 // Compute a function closure that captures the calling context. We
3376 // need a function that has trivial scope info, since it is only
3377 // used to hold the context chain together.
3378 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3379 Factory::undefined_value());
3380 closure->set_context(*caller);
3381
3382 // Create a new adaptor context that has the target environment as
3383 // the extension object. This enables the evaluated code to see both
3384 // the current context with locals and everything and to see global
3385 // variables declared in the target global object. Furthermore, any
3386 // properties introduced with 'var' will be added to the target
3387 // global object because it is the extension object.
3388 Handle<Context> adaptor =
3389 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3390 adaptor->set_extension(target->global());
3391 return *adaptor;
3392}
3393
3394
3395static Object* Runtime_EvalReceiver(Arguments args) {
3396 StackFrameLocator locator;
3397 return locator.FindJavaScriptFrame(1)->receiver();
3398}
3399
3400
3401static Object* Runtime_CompileString(Arguments args) {
3402 HandleScope scope;
ager@chromium.org236ad962008-09-25 09:45:57 +00003403 ASSERT(args.length() == 3);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003404 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00003405 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
3406 bool contextual = args[2]->IsTrue();
3407 RUNTIME_ASSERT(contextual || args[2]->IsFalse());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408
3409 // Compute the eval context.
3410 Handle<Context> context;
3411 if (contextual) {
3412 // Get eval context. May not be available if we are calling eval
3413 // through an alias, and the corresponding frame doesn't have a
3414 // proper eval context set up.
3415 Object* eval_context = EvalContext();
3416 if (eval_context->IsFailure()) return eval_context;
3417 context = Handle<Context>(Context::cast(eval_context));
3418 } else {
3419 context = Handle<Context>(Top::context()->global_context());
3420 }
3421
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003422
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003423 // Compile source string.
3424 bool is_global = context->IsGlobalContext();
3425 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00003426 Compiler::CompileEval(source, line_offset->value(), is_global);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003427 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 Handle<JSFunction> fun =
3429 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3430 return *fun;
3431}
3432
3433
3434static Object* Runtime_CompileScript(Arguments args) {
3435 HandleScope scope;
3436 ASSERT(args.length() == 4);
3437
3438 CONVERT_ARG_CHECKED(String, source, 0);
3439 CONVERT_ARG_CHECKED(String, script, 1);
3440 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3441 int line = line_attrs->value();
3442 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3443 int col = col_attrs->value();
3444 Handle<JSFunction> boilerplate =
3445 Compiler::Compile(source, script, line, col, NULL, NULL);
3446 if (boilerplate.is_null()) return Failure::Exception();
3447 Handle<JSFunction> fun =
3448 Factory::NewFunctionFromBoilerplate(boilerplate,
3449 Handle<Context>(Top::context()));
3450 return *fun;
3451}
3452
3453
3454static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3455 // This utility adjusts the property attributes for newly created Function
3456 // object ("new Function(...)") by changing the map.
3457 // All it does is changing the prototype property to enumerable
3458 // as specified in ECMA262, 15.3.5.2.
3459 HandleScope scope;
3460 ASSERT(args.length() == 1);
3461 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3462 ASSERT(func->map()->instance_type() ==
3463 Top::function_instance_map()->instance_type());
3464 ASSERT(func->map()->instance_size() ==
3465 Top::function_instance_map()->instance_size());
3466 func->set_map(*Top::function_instance_map());
3467 return *func;
3468}
3469
3470
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003471// Push an array unto an array of arrays if it is not already in the
3472// array. Returns true if the element was pushed on the stack and
3473// false otherwise.
3474static Object* Runtime_PushIfAbsent(Arguments args) {
3475 ASSERT(args.length() == 2);
3476 CONVERT_CHECKED(JSArray, array, args[0]);
3477 CONVERT_CHECKED(JSArray, element, args[1]);
3478 RUNTIME_ASSERT(array->HasFastElements());
3479 int length = Smi::cast(array->length())->value();
3480 FixedArray* elements = FixedArray::cast(array->elements());
3481 for (int i = 0; i < length; i++) {
3482 if (elements->get(i) == element) return Heap::false_value();
3483 }
3484 Object* obj = array->SetFastElement(length, element);
3485 if (obj->IsFailure()) return obj;
3486 return Heap::true_value();
3487}
3488
3489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490// This will not allocate (flatten the string), but it may run
3491// very slowly for very deeply nested ConsStrings. For debugging use only.
3492static Object* Runtime_GlobalPrint(Arguments args) {
3493 NoHandleAllocation ha;
3494 ASSERT(args.length() == 1);
3495
3496 CONVERT_CHECKED(String, string, args[0]);
3497 StringInputBuffer buffer(string);
3498 while (buffer.has_more()) {
3499 uint16_t character = buffer.GetNext();
3500 PrintF("%c", character);
3501 }
3502 return string;
3503}
3504
3505
3506static Object* Runtime_RemoveArrayHoles(Arguments args) {
3507 ASSERT(args.length() == 1);
3508 // Ignore the case if this is not a JSArray.
3509 if (!args[0]->IsJSArray()) return args[0];
3510 return JSArray::cast(args[0])->RemoveHoles();
3511}
3512
3513
3514// Move contents of argument 0 (an array) to argument 1 (an array)
3515static Object* Runtime_MoveArrayContents(Arguments args) {
3516 ASSERT(args.length() == 2);
3517 CONVERT_CHECKED(JSArray, from, args[0]);
3518 CONVERT_CHECKED(JSArray, to, args[1]);
3519 to->SetContent(FixedArray::cast(from->elements()));
3520 to->set_length(from->length());
3521 from->SetContent(Heap::empty_fixed_array());
3522 from->set_length(0);
3523 return to;
3524}
3525
3526
3527// How many elements does this array have?
3528static Object* Runtime_EstimateNumberOfElements(Arguments args) {
3529 ASSERT(args.length() == 1);
3530 CONVERT_CHECKED(JSArray, array, args[0]);
3531 HeapObject* elements = array->elements();
3532 if (elements->IsDictionary()) {
3533 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
3534 } else {
3535 return array->length();
3536 }
3537}
3538
3539
3540// Returns an array that tells you where in the [0, length) interval an array
3541// might have elements. Can either return keys or intervals. Keys can have
3542// gaps in (undefined). Intervals can also span over some undefined keys.
3543static Object* Runtime_GetArrayKeys(Arguments args) {
3544 ASSERT(args.length() == 2);
3545 HandleScope scope;
3546 CONVERT_CHECKED(JSArray, raw_array, args[0]);
3547 Handle<JSArray> array(raw_array);
3548 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003549 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003550 // Create an array and get all the keys into it, then remove all the
3551 // keys that are not integers in the range 0 to length-1.
3552 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
3553 int keys_length = keys->length();
3554 for (int i = 0; i < keys_length; i++) {
3555 Object* key = keys->get(i);
3556 uint32_t index;
3557 if (!Array::IndexFromObject(key, &index) || index >= length) {
3558 // Zap invalid keys.
3559 keys->set_undefined(i);
3560 }
3561 }
3562 return *Factory::NewJSArrayWithElements(keys);
3563 } else {
3564 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
3565 // -1 means start of array.
3566 single_interval->set(0, Smi::FromInt(-1));
3567 Handle<Object> length_object =
3568 Factory::NewNumber(static_cast<double>(length));
3569 single_interval->set(1, *length_object);
3570 return *Factory::NewJSArrayWithElements(single_interval);
3571 }
3572}
3573
3574
3575// DefineAccessor takes an optional final argument which is the
3576// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
3577// to the way accessors are implemented, it is set for both the getter
3578// and setter on the first call to DefineAccessor and ignored on
3579// subsequent calls.
3580static Object* Runtime_DefineAccessor(Arguments args) {
3581 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
3582 // Compute attributes.
3583 PropertyAttributes attributes = NONE;
3584 if (args.length() == 5) {
3585 CONVERT_CHECKED(Smi, attrs, args[4]);
3586 int value = attrs->value();
3587 // Only attribute bits should be set.
3588 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3589 attributes = static_cast<PropertyAttributes>(value);
3590 }
3591
3592 CONVERT_CHECKED(JSObject, obj, args[0]);
3593 CONVERT_CHECKED(String, name, args[1]);
3594 CONVERT_CHECKED(Smi, flag, args[2]);
3595 CONVERT_CHECKED(JSFunction, fun, args[3]);
3596 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
3597}
3598
3599
3600static Object* Runtime_LookupAccessor(Arguments args) {
3601 ASSERT(args.length() == 3);
3602 CONVERT_CHECKED(JSObject, obj, args[0]);
3603 CONVERT_CHECKED(String, name, args[1]);
3604 CONVERT_CHECKED(Smi, flag, args[2]);
3605 return obj->LookupAccessor(name, flag->value() == 0);
3606}
3607
3608
3609// Helper functions for wrapping and unwrapping stack frame ids.
3610static Smi* WrapFrameId(StackFrame::Id id) {
3611 ASSERT(IsAligned(OffsetFrom(id), 4));
3612 return Smi::FromInt(id >> 2);
3613}
3614
3615
3616static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
3617 return static_cast<StackFrame::Id>(wrapped->value() << 2);
3618}
3619
3620
3621// Adds a JavaScript function as a debug event listener.
3622// args[0]: debug event listener function
3623// args[1]: object supplied during callback
3624static Object* Runtime_AddDebugEventListener(Arguments args) {
3625 ASSERT(args.length() == 2);
3626 // Convert the parameters to API objects to call the API function for adding
3627 // a JavaScript function as debug event listener.
3628 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3629 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3630 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
3631 v8::Debug::AddDebugEventListener(fun, data);
3632
3633 return Heap::undefined_value();
3634}
3635
3636
3637// Removes a JavaScript function debug event listener.
3638// args[0]: debug event listener function
3639static Object* Runtime_RemoveDebugEventListener(Arguments args) {
3640 ASSERT(args.length() == 1);
3641 // Convert the parameter to an API object to call the API function for
3642 // removing a JavaScript function debug event listener.
3643 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3644 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3645 v8::Debug::RemoveDebugEventListener(fun);
3646
3647 return Heap::undefined_value();
3648}
3649
3650
3651static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003652 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 StackGuard::DebugBreak();
3654 return Heap::undefined_value();
3655}
3656
3657
3658static Object* DebugLookupResultValue(LookupResult* result) {
3659 Object* value;
3660 switch (result->type()) {
3661 case NORMAL: {
3662 Dictionary* dict =
3663 JSObject::cast(result->holder())->property_dictionary();
3664 value = dict->ValueAt(result->GetDictionaryEntry());
3665 if (value->IsTheHole()) {
3666 return Heap::undefined_value();
3667 }
3668 return value;
3669 }
3670 case FIELD:
3671 value =
3672 JSObject::cast(
3673 result->holder())->properties()->get(result->GetFieldIndex());
3674 if (value->IsTheHole()) {
3675 return Heap::undefined_value();
3676 }
3677 return value;
3678 case CONSTANT_FUNCTION:
3679 return result->GetConstantFunction();
3680 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003681 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682 case MAP_TRANSITION:
3683 case CONSTANT_TRANSITION:
3684 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 return Heap::undefined_value();
3686 default:
3687 UNREACHABLE();
3688 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003689 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690 return Heap::undefined_value();
3691}
3692
3693
3694static Object* Runtime_DebugGetLocalPropertyDetails(Arguments args) {
3695 HandleScope scope;
3696
3697 ASSERT(args.length() == 2);
3698
3699 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3700 CONVERT_ARG_CHECKED(String, name, 1);
3701
3702 // Check if the name is trivially convertible to an index and get the element
3703 // if so.
3704 uint32_t index;
3705 if (name->AsArrayIndex(&index)) {
3706 Handle<FixedArray> details = Factory::NewFixedArray(2);
3707 details->set(0, Runtime::GetElementOrCharAt(obj, index));
3708 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
3709 return *Factory::NewJSArrayWithElements(details);
3710 }
3711
3712 // Perform standard local lookup on the object.
3713 LookupResult result;
3714 obj->LocalLookup(*name, &result);
3715 if (result.IsProperty()) {
3716 Handle<Object> value(DebugLookupResultValue(&result));
3717 Handle<FixedArray> details = Factory::NewFixedArray(2);
3718 details->set(0, *value);
3719 details->set(1, result.GetPropertyDetails().AsSmi());
3720 return *Factory::NewJSArrayWithElements(details);
3721 }
3722 return Heap::undefined_value();
3723}
3724
3725
3726static Object* Runtime_DebugGetProperty(Arguments args) {
3727 HandleScope scope;
3728
3729 ASSERT(args.length() == 2);
3730
3731 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3732 CONVERT_ARG_CHECKED(String, name, 1);
3733
3734 LookupResult result;
3735 obj->Lookup(*name, &result);
3736 if (result.IsProperty()) {
3737 return DebugLookupResultValue(&result);
3738 }
3739 return Heap::undefined_value();
3740}
3741
3742
3743// Return the names of the local named properties.
3744// args[0]: object
3745static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
3746 HandleScope scope;
3747 ASSERT(args.length() == 1);
3748 if (!args[0]->IsJSObject()) {
3749 return Heap::undefined_value();
3750 }
3751 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3752
3753 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3754 Handle<FixedArray> names = Factory::NewFixedArray(n);
3755 obj->GetLocalPropertyNames(*names);
3756 return *Factory::NewJSArrayWithElements(names);
3757}
3758
3759
3760// Return the names of the local indexed properties.
3761// args[0]: object
3762static Object* Runtime_DebugLocalElementNames(Arguments args) {
3763 HandleScope scope;
3764 ASSERT(args.length() == 1);
3765 if (!args[0]->IsJSObject()) {
3766 return Heap::undefined_value();
3767 }
3768 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3769
3770 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
3771 Handle<FixedArray> names = Factory::NewFixedArray(n);
3772 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
3773 return *Factory::NewJSArrayWithElements(names);
3774}
3775
3776
3777// Return the property type calculated from the property details.
3778// args[0]: smi with property details.
3779static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
3780 ASSERT(args.length() == 1);
3781 CONVERT_CHECKED(Smi, details, args[0]);
3782 PropertyType type = PropertyDetails(details).type();
3783 return Smi::FromInt(static_cast<int>(type));
3784}
3785
3786
3787// Return the property attribute calculated from the property details.
3788// args[0]: smi with property details.
3789static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
3790 ASSERT(args.length() == 1);
3791 CONVERT_CHECKED(Smi, details, args[0]);
3792 PropertyAttributes attributes = PropertyDetails(details).attributes();
3793 return Smi::FromInt(static_cast<int>(attributes));
3794}
3795
3796
3797// Return the property insertion index calculated from the property details.
3798// args[0]: smi with property details.
3799static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
3800 ASSERT(args.length() == 1);
3801 CONVERT_CHECKED(Smi, details, args[0]);
3802 int index = PropertyDetails(details).index();
3803 return Smi::FromInt(index);
3804}
3805
3806
3807// Return information on whether an object has a named or indexed interceptor.
3808// args[0]: object
3809static Object* Runtime_DebugInterceptorInfo(Arguments args) {
3810 HandleScope scope;
3811 ASSERT(args.length() == 1);
3812 if (!args[0]->IsJSObject()) {
3813 return Smi::FromInt(0);
3814 }
3815 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3816
3817 int result = 0;
3818 if (obj->HasNamedInterceptor()) result |= 2;
3819 if (obj->HasIndexedInterceptor()) result |= 1;
3820
3821 return Smi::FromInt(result);
3822}
3823
3824
3825// Return property names from named interceptor.
3826// args[0]: object
3827static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
3828 HandleScope scope;
3829 ASSERT(args.length() == 1);
3830 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3831 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3832
3833 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
3834 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3835 return Heap::undefined_value();
3836}
3837
3838
3839// Return element names from indexed interceptor.
3840// args[0]: object
3841static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
3842 HandleScope scope;
3843 ASSERT(args.length() == 1);
3844 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3845 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3846
3847 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
3848 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3849 return Heap::undefined_value();
3850}
3851
3852
3853// Return property value from named interceptor.
3854// args[0]: object
3855// args[1]: property name
3856static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
3857 HandleScope scope;
3858 ASSERT(args.length() == 2);
3859 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3860 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3861 CONVERT_ARG_CHECKED(String, name, 1);
3862
3863 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003864 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865}
3866
3867
3868// Return element value from indexed interceptor.
3869// args[0]: object
3870// args[1]: index
3871static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
3872 HandleScope scope;
3873 ASSERT(args.length() == 2);
3874 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3875 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3876 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
3877
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003878 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879}
3880
3881
3882static Object* Runtime_CheckExecutionState(Arguments args) {
3883 ASSERT(args.length() >= 1);
3884 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
3885 // Check that the break id is valid and that there is a valid frame
3886 // where execution is broken.
3887 if (break_id != Top::break_id() ||
3888 Top::break_frame_id() == StackFrame::NO_ID) {
3889 return Top::Throw(Heap::illegal_execution_state_symbol());
3890 }
3891
3892 return Heap::true_value();
3893}
3894
3895
3896static Object* Runtime_GetFrameCount(Arguments args) {
3897 HandleScope scope;
3898 ASSERT(args.length() == 1);
3899
3900 // Check arguments.
3901 Object* result = Runtime_CheckExecutionState(args);
3902 if (result->IsFailure()) return result;
3903
3904 // Count all frames which are relevant to debugging stack trace.
3905 int n = 0;
3906 StackFrame::Id id = Top::break_frame_id();
3907 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
3908 return Smi::FromInt(n);
3909}
3910
3911
3912static const int kFrameDetailsFrameIdIndex = 0;
3913static const int kFrameDetailsReceiverIndex = 1;
3914static const int kFrameDetailsFunctionIndex = 2;
3915static const int kFrameDetailsArgumentCountIndex = 3;
3916static const int kFrameDetailsLocalCountIndex = 4;
3917static const int kFrameDetailsSourcePositionIndex = 5;
3918static const int kFrameDetailsConstructCallIndex = 6;
3919static const int kFrameDetailsDebuggerFrameIndex = 7;
3920static const int kFrameDetailsFirstDynamicIndex = 8;
3921
3922// Return an array with frame details
3923// args[0]: number: break id
3924// args[1]: number: frame index
3925//
3926// The array returned contains the following information:
3927// 0: Frame id
3928// 1: Receiver
3929// 2: Function
3930// 3: Argument count
3931// 4: Local count
3932// 5: Source position
3933// 6: Constructor call
3934// 7: Debugger frame
3935// Arguments name, value
3936// Locals name, value
3937static Object* Runtime_GetFrameDetails(Arguments args) {
3938 HandleScope scope;
3939 ASSERT(args.length() == 2);
3940
3941 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003942 Object* check = Runtime_CheckExecutionState(args);
3943 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
3945
3946 // Find the relevant frame with the requested index.
3947 StackFrame::Id id = Top::break_frame_id();
3948 int count = 0;
3949 JavaScriptFrameIterator it(id);
3950 for (; !it.done(); it.Advance()) {
3951 if (count == index) break;
3952 count++;
3953 }
3954 if (it.done()) return Heap::undefined_value();
3955
3956 // Traverse the saved contexts chain to find the active context for the
3957 // selected frame.
3958 SaveContext* save = Top::save_context();
3959 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
3960 save = save->prev();
3961 }
3962
3963 // Get the frame id.
3964 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
3965
3966 // Find source position.
3967 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
3968
3969 // Check for constructor frame.
3970 bool constructor = it.frame()->IsConstructor();
3971
3972 // Get code and read scope info from it for local variable information.
3973 Handle<Code> code(it.frame()->FindCode());
3974 ScopeInfo<> info(*code);
3975
3976 // Get the context.
3977 Handle<Context> context(Context::cast(it.frame()->context()));
3978
3979 // Get the locals names and values into a temporary array.
3980 //
3981 // TODO(1240907): Hide compiler-introduced stack variables
3982 // (e.g. .result)? For users of the debugger, they will probably be
3983 // confusing.
3984 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
3985 for (int i = 0; i < info.NumberOfLocals(); i++) {
3986 // Name of the local.
3987 locals->set(i * 2, *info.LocalName(i));
3988
3989 // Fetch the value of the local - either from the stack or from a
3990 // heap-allocated context.
3991 if (i < info.number_of_stack_slots()) {
3992 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
3993 } else {
3994 Handle<String> name = info.LocalName(i);
3995 // Traverse the context chain to the function context as all local
3996 // variables stored in the context will be on the function context.
3997 while (context->previous() != NULL) {
3998 context = Handle<Context>(context->previous());
3999 }
4000 ASSERT(context->is_function_context());
4001 locals->set(i * 2 + 1,
4002 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
4003 NULL)));
4004 }
4005 }
4006
4007 // Now advance to the arguments adapter frame (if any). If contains all
4008 // the provided parameters and
4009
4010 // Now advance to the arguments adapter frame (if any). It contains all
4011 // the provided parameters whereas the function frame always have the number
4012 // of arguments matching the functions parameters. The rest of the
4013 // information (except for what is collected above) is the same.
4014 it.AdvanceToArgumentsFrame();
4015
4016 // Find the number of arguments to fill. At least fill the number of
4017 // parameters for the function and fill more if more parameters are provided.
4018 int argument_count = info.number_of_parameters();
4019 if (argument_count < it.frame()->GetProvidedParametersCount()) {
4020 argument_count = it.frame()->GetProvidedParametersCount();
4021 }
4022
4023 // Calculate the size of the result.
4024 int details_size = kFrameDetailsFirstDynamicIndex +
4025 2 * (argument_count + info.NumberOfLocals());
4026 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
4027
4028 // Add the frame id.
4029 details->set(kFrameDetailsFrameIdIndex, *frame_id);
4030
4031 // Add the function (same as in function frame).
4032 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
4033
4034 // Add the arguments count.
4035 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
4036
4037 // Add the locals count
4038 details->set(kFrameDetailsLocalCountIndex,
4039 Smi::FromInt(info.NumberOfLocals()));
4040
4041 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00004042 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
4044 } else {
4045 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
4046 }
4047
4048 // Add the constructor information.
4049 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
4050
4051 // Add information on whether this frame is invoked in the debugger context.
4052 details->set(kFrameDetailsDebuggerFrameIndex,
4053 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
4054
4055 // Fill the dynamic part.
4056 int details_index = kFrameDetailsFirstDynamicIndex;
4057
4058 // Add arguments name and value.
4059 for (int i = 0; i < argument_count; i++) {
4060 // Name of the argument.
4061 if (i < info.number_of_parameters()) {
4062 details->set(details_index++, *info.parameter_name(i));
4063 } else {
4064 details->set(details_index++, Heap::undefined_value());
4065 }
4066
4067 // Parameter value.
4068 if (i < it.frame()->GetProvidedParametersCount()) {
4069 details->set(details_index++, it.frame()->GetParameter(i));
4070 } else {
4071 details->set(details_index++, Heap::undefined_value());
4072 }
4073 }
4074
4075 // Add locals name and value from the temporary copy from the function frame.
4076 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
4077 details->set(details_index++, locals->get(i));
4078 }
4079
4080 // Add the receiver (same as in function frame).
4081 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
4082 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
4083 Handle<Object> receiver(it.frame()->receiver());
4084 if (!receiver->IsJSObject()) {
4085 // If the receiver is NOT a JSObject we have hit an optimization
4086 // where a value object is not converted into a wrapped JS objects.
4087 // To hide this optimization from the debugger, we wrap the receiver
4088 // by creating correct wrapper object based on the calling frame's
4089 // global context.
4090 it.Advance();
4091 Handle<Context> calling_frames_global_context(
4092 Context::cast(Context::cast(it.frame()->context())->global_context()));
4093 receiver = Factory::ToObject(receiver, calling_frames_global_context);
4094 }
4095 details->set(kFrameDetailsReceiverIndex, *receiver);
4096
4097 ASSERT_EQ(details_size, details_index);
4098 return *Factory::NewJSArrayWithElements(details);
4099}
4100
4101
4102static Object* Runtime_GetCFrames(Arguments args) {
4103 HandleScope scope;
4104 ASSERT(args.length() == 1);
4105 Object* result = Runtime_CheckExecutionState(args);
4106 if (result->IsFailure()) return result;
4107
4108 static const int kMaxCFramesSize = 200;
4109 OS::StackFrame frames[kMaxCFramesSize];
4110 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4111 if (frames_count == OS::kStackWalkError) {
4112 return Heap::undefined_value();
4113 }
4114
4115 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4116 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4117 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4118 for (int i = 0; i < frames_count; i++) {
4119 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4120 frame_value->SetProperty(
4121 *address_str,
4122 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4123 NONE);
4124
4125 // Get the stack walk text for this frame.
4126 Handle<String> frame_text;
4127 if (strlen(frames[i].text) > 0) {
4128 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4129 frame_text = Factory::NewStringFromAscii(str);
4130 }
4131
4132 if (!frame_text.is_null()) {
4133 frame_value->SetProperty(*text_str, *frame_text, NONE);
4134 }
4135
4136 frames_array->set(i, *frame_value);
4137 }
4138 return *Factory::NewJSArrayWithElements(frames_array);
4139}
4140
4141
4142static Object* Runtime_GetBreakLocations(Arguments args) {
4143 HandleScope scope;
4144 ASSERT(args.length() == 1);
4145
4146 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4147 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4148 // Find the number of break points
4149 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4150 if (break_locations->IsUndefined()) return Heap::undefined_value();
4151 // Return array as JS array
4152 return *Factory::NewJSArrayWithElements(
4153 Handle<FixedArray>::cast(break_locations));
4154}
4155
4156
4157// Set a break point in a function
4158// args[0]: function
4159// args[1]: number: break source position (within the function source)
4160// args[2]: number: break point object
4161static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4162 HandleScope scope;
4163 ASSERT(args.length() == 3);
4164 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4165 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4166 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4167 RUNTIME_ASSERT(source_position >= 0);
4168 Handle<Object> break_point_object_arg = args.at<Object>(2);
4169
4170 // Set break point.
4171 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4172
4173 return Heap::undefined_value();
4174}
4175
4176
4177static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4178 int position) {
4179 // Iterate the heap looking for SharedFunctionInfo generated from the
4180 // script. The inner most SharedFunctionInfo containing the source position
4181 // for the requested break point is found.
4182 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4183 // which is found is not compiled it is compiled and the heap is iterated
4184 // again as the compilation might create inner functions from the newly
4185 // compiled function and the actual requested break point might be in one of
4186 // these functions.
4187 bool done = false;
4188 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00004189 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 Handle<SharedFunctionInfo> target;
4191 // The current candidate for the last function in script:
4192 Handle<SharedFunctionInfo> last;
4193 while (!done) {
4194 HeapIterator iterator;
4195 while (iterator.has_next()) {
4196 HeapObject* obj = iterator.next();
4197 ASSERT(obj != NULL);
4198 if (obj->IsSharedFunctionInfo()) {
4199 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4200 if (shared->script() == *script) {
4201 // If the SharedFunctionInfo found has the requested script data and
4202 // contains the source position it is a candidate.
4203 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00004204 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 start_position = shared->start_position();
4206 }
4207 if (start_position <= position &&
4208 position <= shared->end_position()) {
4209 // If there is no candidate or this function is within the currrent
4210 // candidate this is the new candidate.
4211 if (target.is_null()) {
4212 target_start_position = start_position;
4213 target = shared;
4214 } else {
4215 if (target_start_position < start_position &&
4216 shared->end_position() < target->end_position()) {
4217 target_start_position = start_position;
4218 target = shared;
4219 }
4220 }
4221 }
4222
4223 // Keep track of the last function in the script.
4224 if (last.is_null() ||
4225 shared->end_position() > last->start_position()) {
4226 last = shared;
4227 }
4228 }
4229 }
4230 }
4231
4232 // Make sure some candidate is selected.
4233 if (target.is_null()) {
4234 if (!last.is_null()) {
4235 // Position after the last function - use last.
4236 target = last;
4237 } else {
4238 // Unable to find function - possibly script without any function.
4239 return Heap::undefined_value();
4240 }
4241 }
4242
4243 // If the candidate found is compiled we are done. NOTE: when lazy
4244 // compilation of inner functions is introduced some additional checking
4245 // needs to be done here to compile inner functions.
4246 done = target->is_compiled();
4247 if (!done) {
4248 // If the candidate is not compiled compile it to reveal any inner
4249 // functions which might contain the requested source position.
4250 CompileLazyShared(target, KEEP_EXCEPTION);
4251 }
4252 }
4253
4254 return *target;
4255}
4256
4257
4258// Change the state of a break point in a script. NOTE: Regarding performance
4259// see the NOTE for GetScriptFromScriptData.
4260// args[0]: script to set break point in
4261// args[1]: number: break source position (within the script source)
4262// args[2]: number: break point object
4263static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4264 HandleScope scope;
4265 ASSERT(args.length() == 3);
4266 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4267 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4268 RUNTIME_ASSERT(source_position >= 0);
4269 Handle<Object> break_point_object_arg = args.at<Object>(2);
4270
4271 // Get the script from the script wrapper.
4272 RUNTIME_ASSERT(wrapper->value()->IsScript());
4273 Handle<Script> script(Script::cast(wrapper->value()));
4274
4275 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4276 if (!result->IsUndefined()) {
4277 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4278 // Find position within function. The script position might be before the
4279 // source position of the first function.
4280 int position;
4281 if (shared->start_position() > source_position) {
4282 position = 0;
4283 } else {
4284 position = source_position - shared->start_position();
4285 }
4286 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4287 }
4288 return Heap::undefined_value();
4289}
4290
4291
4292// Clear a break point
4293// args[0]: number: break point object
4294static Object* Runtime_ClearBreakPoint(Arguments args) {
4295 HandleScope scope;
4296 ASSERT(args.length() == 1);
4297 Handle<Object> break_point_object_arg = args.at<Object>(0);
4298
4299 // Clear break point.
4300 Debug::ClearBreakPoint(break_point_object_arg);
4301
4302 return Heap::undefined_value();
4303}
4304
4305
4306// Change the state of break on exceptions
4307// args[0]: boolean indicating uncaught exceptions
4308// args[1]: boolean indicating on/off
4309static Object* Runtime_ChangeBreakOnException(Arguments args) {
4310 HandleScope scope;
4311 ASSERT(args.length() == 2);
4312 ASSERT(args[0]->IsNumber());
4313 ASSERT(args[1]->IsBoolean());
4314
4315 // Update break point state
4316 ExceptionBreakType type =
4317 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4318 bool enable = args[1]->ToBoolean()->IsTrue();
4319 Debug::ChangeBreakOnException(type, enable);
4320 return Heap::undefined_value();
4321}
4322
4323
4324// Prepare for stepping
4325// args[0]: break id for checking execution state
4326// args[1]: step action from the enumeration StepAction
4327// args[2]: number of times to perform the step
4328static Object* Runtime_PrepareStep(Arguments args) {
4329 HandleScope scope;
4330 ASSERT(args.length() == 3);
4331 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004332 Object* check = Runtime_CheckExecutionState(args);
4333 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4335 return Top::Throw(Heap::illegal_argument_symbol());
4336 }
4337
4338 // Get the step action and check validity.
4339 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4340 if (step_action != StepIn &&
4341 step_action != StepNext &&
4342 step_action != StepOut &&
4343 step_action != StepInMin &&
4344 step_action != StepMin) {
4345 return Top::Throw(Heap::illegal_argument_symbol());
4346 }
4347
4348 // Get the number of steps.
4349 int step_count = NumberToInt32(args[2]);
4350 if (step_count < 1) {
4351 return Top::Throw(Heap::illegal_argument_symbol());
4352 }
4353
4354 // Prepare step.
4355 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4356 return Heap::undefined_value();
4357}
4358
4359
4360// Clear all stepping set by PrepareStep.
4361static Object* Runtime_ClearStepping(Arguments args) {
4362 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004363 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004364 Debug::ClearStepping();
4365 return Heap::undefined_value();
4366}
4367
4368
4369// Creates a copy of the with context chain. The copy of the context chain is
4370// is linked to the function context supplied.
4371static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4372 Handle<Context> function_context) {
4373 // At the bottom of the chain. Return the function context to link to.
4374 if (context_chain->is_function_context()) {
4375 return function_context;
4376 }
4377
4378 // Recursively copy the with contexts.
4379 Handle<Context> previous(context_chain->previous());
4380 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4381 return Factory::NewWithContext(
4382 CopyWithContextChain(function_context, previous), extension);
4383}
4384
4385
4386// Helper function to find or create the arguments object for
4387// Runtime_DebugEvaluate.
4388static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4389 Handle<JSFunction> function,
4390 Handle<Code> code,
4391 const ScopeInfo<>* sinfo,
4392 Handle<Context> function_context) {
4393 // Try to find the value of 'arguments' to pass as parameter. If it is not
4394 // found (that is the debugged function does not reference 'arguments' and
4395 // does not support eval) then create an 'arguments' object.
4396 int index;
4397 if (sinfo->number_of_stack_slots() > 0) {
4398 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4399 if (index != -1) {
4400 return Handle<Object>(frame->GetExpression(index));
4401 }
4402 }
4403
4404 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4405 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4406 NULL);
4407 if (index != -1) {
4408 return Handle<Object>(function_context->get(index));
4409 }
4410 }
4411
4412 const int length = frame->GetProvidedParametersCount();
4413 Handle<Object> arguments = Factory::NewArgumentsObject(function, length);
4414 FixedArray* array = FixedArray::cast(JSObject::cast(*arguments)->elements());
4415 ASSERT(array->length() == length);
4416 for (int i = 0; i < length; i++) {
4417 array->set(i, frame->GetParameter(i));
4418 }
4419 return arguments;
4420}
4421
4422
4423// Evaluate a piece of JavaScript in the context of a stack frame for
4424// debugging. This is acomplished by creating a new context which in its
4425// extension part has all the parameters and locals of the function on the
4426// stack frame. A function which calls eval with the code to evaluate is then
4427// compiled in this context and called in this context. As this context
4428// replaces the context of the function on the stack frame a new (empty)
4429// function is created as well to be used as the closure for the context.
4430// This function and the context acts as replacements for the function on the
4431// stack frame presenting the same view of the values of parameters and
4432// local variables as if the piece of JavaScript was evaluated at the point
4433// where the function on the stack frame is currently stopped.
4434static Object* Runtime_DebugEvaluate(Arguments args) {
4435 HandleScope scope;
4436
4437 // Check the execution state and decode arguments frame and source to be
4438 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004439 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 Object* check_result = Runtime_CheckExecutionState(args);
4441 if (check_result->IsFailure()) return check_result;
4442 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4443 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004444 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4445
4446 // Handle the processing of break.
4447 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448
4449 // Get the frame where the debugging is performed.
4450 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4451 JavaScriptFrameIterator it(id);
4452 JavaScriptFrame* frame = it.frame();
4453 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4454 Handle<Code> code(function->code());
4455 ScopeInfo<> sinfo(*code);
4456
4457 // Traverse the saved contexts chain to find the active context for the
4458 // selected frame.
4459 SaveContext* save = Top::save_context();
4460 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4461 save = save->prev();
4462 }
4463 ASSERT(save != NULL);
4464 SaveContext savex;
4465 Top::set_context(*(save->context()));
4466 Top::set_security_context(*(save->security_context()));
4467
4468 // Create the (empty) function replacing the function on the stack frame for
4469 // the purpose of evaluating in the context created below. It is important
4470 // that this function does not describe any parameters and local variables
4471 // in the context. If it does then this will cause problems with the lookup
4472 // in Context::Lookup, where context slots for parameters and local variables
4473 // are looked at before the extension object.
4474 Handle<JSFunction> go_between =
4475 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4476 go_between->set_context(function->context());
4477#ifdef DEBUG
4478 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4479 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4480 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4481#endif
4482
4483 // Allocate and initialize a context extension object with all the
4484 // arguments, stack locals heap locals and extension properties of the
4485 // debugged function.
4486 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4487 // First fill all parameters to the context extension.
4488 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4489 SetProperty(context_ext,
4490 sinfo.parameter_name(i),
4491 Handle<Object>(frame->GetParameter(i)), NONE);
4492 }
4493 // Second fill all stack locals to the context extension.
4494 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4495 SetProperty(context_ext,
4496 sinfo.stack_slot_name(i),
4497 Handle<Object>(frame->GetExpression(i)), NONE);
4498 }
4499 // Third fill all context locals to the context extension.
4500 Handle<Context> frame_context(Context::cast(frame->context()));
4501 Handle<Context> function_context(frame_context->fcontext());
4502 for (int i = Context::MIN_CONTEXT_SLOTS;
4503 i < sinfo.number_of_context_slots();
4504 ++i) {
4505 int context_index =
4506 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
4507 SetProperty(context_ext,
4508 sinfo.context_slot_name(i),
4509 Handle<Object>(function_context->get(context_index)), NONE);
4510 }
4511 // Finally copy any properties from the function context extension. This will
4512 // be variables introduced by eval.
4513 if (function_context->extension() != NULL &&
4514 !function_context->IsGlobalContext()) {
4515 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
4516 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
4517 for (int i = 0; i < keys->length(); i++) {
4518 // Names of variables introduced by eval are strings.
4519 ASSERT(keys->get(i)->IsString());
4520 Handle<String> key(String::cast(keys->get(i)));
4521 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
4522 }
4523 }
4524
4525 // Allocate a new context for the debug evaluation and set the extension
4526 // object build.
4527 Handle<Context> context =
4528 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
4529 context->set_extension(*context_ext);
4530 // Copy any with contexts present and chain them in front of this context.
4531 context = CopyWithContextChain(frame_context, context);
4532
4533 // Wrap the evaluation statement in a new function compiled in the newly
4534 // created context. The function has one parameter which has to be called
4535 // 'arguments'. This it to have access to what would have been 'arguments' in
4536 // the function beeing debugged.
4537 // function(arguments,__source__) {return eval(__source__);}
4538 static const char* source_str =
4539 "function(arguments,__source__){return eval(__source__);}";
4540 static const int source_str_length = strlen(source_str);
4541 Handle<String> function_source =
4542 Factory::NewStringFromAscii(Vector<const char>(source_str,
4543 source_str_length));
4544 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00004545 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 if (boilerplate.is_null()) return Failure::Exception();
4547 Handle<JSFunction> compiled_function =
4548 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4549
4550 // Invoke the result of the compilation to get the evaluation function.
4551 bool has_pending_exception;
4552 Handle<Object> receiver(frame->receiver());
4553 Handle<Object> evaluation_function =
4554 Execution::Call(compiled_function, receiver, 0, NULL,
4555 &has_pending_exception);
4556
4557 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
4558 function_context);
4559
4560 // Invoke the evaluation function and return the result.
4561 const int argc = 2;
4562 Object** argv[argc] = { arguments.location(),
4563 Handle<Object>::cast(source).location() };
4564 Handle<Object> result =
4565 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
4566 argc, argv, &has_pending_exception);
4567 return *result;
4568}
4569
4570
4571static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
4572 HandleScope scope;
4573
4574 // Check the execution state and decode arguments frame and source to be
4575 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004576 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 Object* check_result = Runtime_CheckExecutionState(args);
4578 if (check_result->IsFailure()) return check_result;
4579 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004580 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
4581
4582 // Handle the processing of break.
4583 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584
4585 // Enter the top context from before the debugger was invoked.
4586 SaveContext save;
4587 SaveContext* top = &save;
4588 while (top != NULL && *top->context() == *Debug::debug_context()) {
4589 top = top->prev();
4590 }
4591 if (top != NULL) {
4592 Top::set_context(*top->context());
4593 Top::set_security_context(*top->security_context());
4594 }
4595
4596 // Get the global context now set to the top context from before the
4597 // debugger was invoked.
4598 Handle<Context> context = Top::global_context();
4599
4600 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00004601 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 if (boilerplate.is_null()) return Failure::Exception();
4603 Handle<JSFunction> compiled_function =
4604 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
4605 context));
4606
4607 // Invoke the result of the compilation to get the evaluation function.
4608 bool has_pending_exception;
4609 Handle<Object> receiver = Top::global();
4610 Handle<Object> result =
4611 Execution::Call(compiled_function, receiver, 0, NULL,
4612 &has_pending_exception);
4613 return *result;
4614}
4615
4616
4617// Helper function used by Runtime_DebugGetLoadedScripts below.
4618static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
4619 NoHandleAllocation ha;
4620 AssertNoAllocation no_alloc;
4621
4622 // Get hold of the current empty script.
4623 Context* context = Top::context()->global_context();
4624 Script* empty = context->empty_script();
4625
4626 // Scan heap for Script objects.
4627 int count = 0;
4628 HeapIterator iterator;
4629 while (iterator.has_next()) {
4630 HeapObject* obj = iterator.next();
4631 ASSERT(obj != NULL);
4632 if (obj->IsScript() && obj != empty) {
4633 if (instances != NULL && count < instances_size) {
4634 instances->set(count, obj);
4635 }
4636 count++;
4637 }
4638 }
4639
4640 return count;
4641}
4642
4643
4644static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
4645 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004646 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004647
4648 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
4649 // rid of all the cached script wrappes and the second gets rid of the
4650 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004651 Heap::CollectAllGarbage();
4652 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653
4654 // Get the number of scripts.
4655 int count;
4656 count = DebugGetLoadedScripts(NULL, 0);
4657
4658 // Allocate an array to hold the result.
4659 Handle<FixedArray> instances = Factory::NewFixedArray(count);
4660
4661 // Fill the script objects.
4662 count = DebugGetLoadedScripts(*instances, count);
4663
4664 // Convert the script objects to proper JS objects.
4665 for (int i = 0; i < count; i++) {
4666 Handle<Script> script(Script::cast(instances->get(i)));
4667 instances->set(i, *GetScriptWrapper(script));
4668 }
4669
4670 // Return result as a JS array.
4671 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
4672 Handle<JSArray>::cast(result)->SetContent(*instances);
4673 return *result;
4674}
4675
4676
4677// Helper function used by Runtime_DebugReferencedBy below.
4678static int DebugReferencedBy(JSObject* target,
4679 Object* instance_filter, int max_references,
4680 FixedArray* instances, int instances_size,
4681 JSFunction* context_extension_function,
4682 JSFunction* arguments_function) {
4683 NoHandleAllocation ha;
4684 AssertNoAllocation no_alloc;
4685
4686 // Iterate the heap.
4687 int count = 0;
4688 JSObject* last = NULL;
4689 HeapIterator iterator;
4690 while (iterator.has_next() &&
4691 (max_references == 0 || count < max_references)) {
4692 // Only look at all JSObjects.
4693 HeapObject* heap_obj = iterator.next();
4694 if (heap_obj->IsJSObject()) {
4695 // Skip context extension objects and argument arrays as these are
4696 // checked in the context of functions using them.
4697 JSObject* obj = JSObject::cast(heap_obj);
4698 if (obj->map()->constructor() == context_extension_function ||
4699 obj->map()->constructor() == arguments_function) {
4700 continue;
4701 }
4702
4703 // Check if the JS object has a reference to the object looked for.
4704 if (obj->ReferencesObject(target)) {
4705 // Check instance filter if supplied. This is normally used to avoid
4706 // references from mirror objects (see Runtime_IsInPrototypeChain).
4707 if (!instance_filter->IsUndefined()) {
4708 Object* V = obj;
4709 while (true) {
4710 Object* prototype = V->GetPrototype();
4711 if (prototype->IsNull()) {
4712 break;
4713 }
4714 if (instance_filter == prototype) {
4715 obj = NULL; // Don't add this object.
4716 break;
4717 }
4718 V = prototype;
4719 }
4720 }
4721
4722 if (obj != NULL) {
4723 // Valid reference found add to instance array if supplied an update
4724 // count.
4725 if (instances != NULL && count < instances_size) {
4726 instances->set(count, obj);
4727 }
4728 last = obj;
4729 count++;
4730 }
4731 }
4732 }
4733 }
4734
4735 // Check for circular reference only. This can happen when the object is only
4736 // referenced from mirrors and has a circular reference in which case the
4737 // object is not really alive and would have been garbage collected if not
4738 // referenced from the mirror.
4739 if (count == 1 && last == target) {
4740 count = 0;
4741 }
4742
4743 // Return the number of referencing objects found.
4744 return count;
4745}
4746
4747
4748// Scan the heap for objects with direct references to an object
4749// args[0]: the object to find references to
4750// args[1]: constructor function for instances to exclude (Mirror)
4751// args[2]: the the maximum number of objects to return
4752static Object* Runtime_DebugReferencedBy(Arguments args) {
4753 ASSERT(args.length() == 3);
4754
4755 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004756 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757
4758 // Check parameters.
4759 CONVERT_CHECKED(JSObject, target, args[0]);
4760 Object* instance_filter = args[1];
4761 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
4762 instance_filter->IsJSObject());
4763 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
4764 RUNTIME_ASSERT(max_references >= 0);
4765
4766 // Get the constructor function for context extension and arguments array.
4767 JSFunction* context_extension_function =
4768 Top::context()->global_context()->context_extension_function();
4769 JSObject* arguments_boilerplate =
4770 Top::context()->global_context()->arguments_boilerplate();
4771 JSFunction* arguments_function =
4772 JSFunction::cast(arguments_boilerplate->map()->constructor());
4773
4774 // Get the number of referencing objects.
4775 int count;
4776 count = DebugReferencedBy(target, instance_filter, max_references,
4777 NULL, 0,
4778 context_extension_function, arguments_function);
4779
4780 // Allocate an array to hold the result.
4781 Object* object = Heap::AllocateFixedArray(count);
4782 if (object->IsFailure()) return object;
4783 FixedArray* instances = FixedArray::cast(object);
4784
4785 // Fill the referencing objects.
4786 count = DebugReferencedBy(target, instance_filter, max_references,
4787 instances, count,
4788 context_extension_function, arguments_function);
4789
4790 // Return result as JS array.
4791 Object* result =
4792 Heap::AllocateJSObject(
4793 Top::context()->global_context()->array_function());
4794 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4795 return result;
4796}
4797
4798
4799// Helper function used by Runtime_DebugConstructedBy below.
4800static int DebugConstructedBy(JSFunction* constructor, int max_references,
4801 FixedArray* instances, int instances_size) {
4802 AssertNoAllocation no_alloc;
4803
4804 // Iterate the heap.
4805 int count = 0;
4806 HeapIterator iterator;
4807 while (iterator.has_next() &&
4808 (max_references == 0 || count < max_references)) {
4809 // Only look at all JSObjects.
4810 HeapObject* heap_obj = iterator.next();
4811 if (heap_obj->IsJSObject()) {
4812 JSObject* obj = JSObject::cast(heap_obj);
4813 if (obj->map()->constructor() == constructor) {
4814 // Valid reference found add to instance array if supplied an update
4815 // count.
4816 if (instances != NULL && count < instances_size) {
4817 instances->set(count, obj);
4818 }
4819 count++;
4820 }
4821 }
4822 }
4823
4824 // Return the number of referencing objects found.
4825 return count;
4826}
4827
4828
4829// Scan the heap for objects constructed by a specific function.
4830// args[0]: the constructor to find instances of
4831// args[1]: the the maximum number of objects to return
4832static Object* Runtime_DebugConstructedBy(Arguments args) {
4833 ASSERT(args.length() == 2);
4834
4835 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004836 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837
4838 // Check parameters.
4839 CONVERT_CHECKED(JSFunction, constructor, args[0]);
4840 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
4841 RUNTIME_ASSERT(max_references >= 0);
4842
4843 // Get the number of referencing objects.
4844 int count;
4845 count = DebugConstructedBy(constructor, max_references, NULL, 0);
4846
4847 // Allocate an array to hold the result.
4848 Object* object = Heap::AllocateFixedArray(count);
4849 if (object->IsFailure()) return object;
4850 FixedArray* instances = FixedArray::cast(object);
4851
4852 // Fill the referencing objects.
4853 count = DebugConstructedBy(constructor, max_references, instances, count);
4854
4855 // Return result as JS array.
4856 Object* result =
4857 Heap::AllocateJSObject(
4858 Top::context()->global_context()->array_function());
4859 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4860 return result;
4861}
4862
4863
4864static Object* Runtime_GetPrototype(Arguments args) {
4865 ASSERT(args.length() == 1);
4866
4867 CONVERT_CHECKED(JSObject, obj, args[0]);
4868
4869 return obj->GetPrototype();
4870}
4871
4872
4873static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004874 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004875 CPU::DebugBreak();
4876 return Heap::undefined_value();
4877}
4878
4879
4880// Finds the script object from the script data. NOTE: This operation uses
4881// heap traversal to find the function generated for the source position
4882// for the requested break point. For lazily compiled functions several heap
4883// traversals might be required rendering this operation as a rather slow
4884// operation. However for setting break points which is normally done through
4885// some kind of user interaction the performance is not crucial.
4886static Handle<Object> Runtime_GetScriptFromScriptName(
4887 Handle<String> script_name) {
4888 // Scan the heap for Script objects to find the script with the requested
4889 // script data.
4890 Handle<Script> script;
4891 HeapIterator iterator;
4892 while (script.is_null() && iterator.has_next()) {
4893 HeapObject* obj = iterator.next();
4894 // If a script is found check if it has the script data requested.
4895 if (obj->IsScript()) {
4896 if (Script::cast(obj)->name()->IsString()) {
4897 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
4898 script = Handle<Script>(Script::cast(obj));
4899 }
4900 }
4901 }
4902 }
4903
4904 // If no script with the requested script data is found return undefined.
4905 if (script.is_null()) return Factory::undefined_value();
4906
4907 // Return the script found.
4908 return GetScriptWrapper(script);
4909}
4910
4911
4912// Get the script object from script data. NOTE: Regarding performance
4913// see the NOTE for GetScriptFromScriptData.
4914// args[0]: script data for the script to find the source for
4915static Object* Runtime_GetScript(Arguments args) {
4916 HandleScope scope;
4917
4918 ASSERT(args.length() == 1);
4919
4920 CONVERT_CHECKED(String, script_name, args[0]);
4921
4922 // Find the requested script.
4923 Handle<Object> result =
4924 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
4925 return *result;
4926}
4927
4928
4929static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
4930#ifdef DEBUG
4931 HandleScope scope;
4932 ASSERT(args.length() == 1);
4933 // Get the function and make sure it is compiled.
4934 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4935 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
4936 return Failure::Exception();
4937 }
4938 func->code()->PrintLn();
4939#endif // DEBUG
4940 return Heap::undefined_value();
4941}
4942
4943
4944static Object* Runtime_Abort(Arguments args) {
4945 ASSERT(args.length() == 2);
4946 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
4947 Smi::cast(args[1])->value());
4948 Top::PrintStack();
4949 OS::Abort();
4950 UNREACHABLE();
4951 return NULL;
4952}
4953
4954
kasper.lund44510672008-07-25 07:37:58 +00004955#ifdef DEBUG
4956// ListNatives is ONLY used by the fuzz-natives.js in debug mode
4957// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004958static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004959 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 HandleScope scope;
4961 Handle<JSArray> result = Factory::NewJSArray(0);
4962 int index = 0;
4963#define ADD_ENTRY(Name, argc) \
4964 { \
4965 HandleScope inner; \
4966 Handle<String> name = \
4967 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
4968 Handle<JSArray> pair = Factory::NewJSArray(0); \
4969 SetElement(pair, 0, name); \
4970 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
4971 SetElement(result, index++, pair); \
4972 }
4973 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
4974#undef ADD_ENTRY
4975 return *result;
4976}
kasper.lund44510672008-07-25 07:37:58 +00004977#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978
4979
4980static Object* Runtime_IS_VAR(Arguments args) {
4981 UNREACHABLE(); // implemented as macro in the parser
4982 return NULL;
4983}
4984
4985
4986// ----------------------------------------------------------------------------
4987// Implementation of Runtime
4988
4989#define F(name, nargs) \
4990 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
4991 static_cast<int>(Runtime::k##name) },
4992
4993static Runtime::Function Runtime_functions[] = {
4994 RUNTIME_FUNCTION_LIST(F)
4995 { NULL, NULL, NULL, 0, -1 }
4996};
4997
4998#undef F
4999
5000
5001Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
5002 ASSERT(0 <= fid && fid < kNofFunctions);
5003 return &Runtime_functions[fid];
5004}
5005
5006
5007Runtime::Function* Runtime::FunctionForName(const char* name) {
5008 for (Function* f = Runtime_functions; f->name != NULL; f++) {
5009 if (strcmp(f->name, name) == 0) {
5010 return f;
5011 }
5012 }
5013 return NULL;
5014}
5015
5016
5017void Runtime::PerformGC(Object* result) {
5018 Failure* failure = Failure::cast(result);
5019 // Try to do a garbage collection; ignore it if it fails. The C
5020 // entry stub will throw an out-of-memory exception in that case.
5021 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5022}
5023
5024
5025} } // namespace v8::internal