blob: e894bf242cbb5b0a298910226d234e842646c2e8 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000046#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000047#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000048#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000049#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000050#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000055#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64
ager@chromium.org3e875802009-06-29 08:26:34 +000065#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68// Cast the given object to a value of the specified type and store
69// it in a variable with the given name. If the object is not of the
70// expected type call IllegalOperation and return.
71#define CONVERT_CHECKED(Type, name, obj) \
72 RUNTIME_ASSERT(obj->Is##Type()); \
73 Type* name = Type::cast(obj);
74
75#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
77 Handle<Type> name = args.at<Type>(index);
78
kasper.lundbd3ec4e2008-07-09 11:06:54 +000079// Cast the given object to a boolean and store it in a variable with
80// the given name. If the object is not a boolean call IllegalOperation
81// and return.
82#define CONVERT_BOOLEAN_CHECKED(name, obj) \
83 RUNTIME_ASSERT(obj->IsBoolean()); \
84 bool name = (obj)->IsTrue();
85
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086// Cast the given argument to a Smi and store its value in an int variable
87// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000088// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000089#define CONVERT_SMI_ARG_CHECKED(name, index) \
90 RUNTIME_ASSERT(args[index]->IsSmi()); \
91 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093// Cast the given argument to a double and store it in a variable with
94// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000096#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
97 RUNTIME_ASSERT(args[index]->IsNumber()); \
98 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100// Call the specified converter on the object *comand store the result in
101// a variable of the specified type with the given name. If the
102// object is not a Number call IllegalOperation and return.
103#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
104 RUNTIME_ASSERT(obj->IsNumber()); \
105 type name = NumberTo##Type(obj);
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
109 JSObject* boilerplate) {
110 StackLimitCheck check(isolate);
111 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000116 if (!maybe_result->ToObject(&result)) return maybe_result;
117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 JSObject* copy = JSObject::cast(result);
119
120 // Deep copy local properties.
121 if (copy->HasFastProperties()) {
122 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 for (int i = 0; i < properties->length(); i++) {
124 Object* value = properties->get(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 }
132 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000133 int nof = copy->map()->inobject_properties();
134 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 Object* value = copy->InObjectPropertyAt(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
144 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 FixedArray* names = FixedArray::cast(result);
150 copy->GetLocalPropertyNames(names, 0);
151 for (int i = 0; i < names->length(); i++) {
152 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 // Only deep copy fields from the object literal expression.
157 // In particular, don't try to copy the length attribute of
158 // an array.
159 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 Object* value =
161 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 if (!maybe_result->ToObject(&result)) return maybe_result;
166 }
167 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000168 // Creating object copy for literals. No strict mode needed.
169 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 }
175
176 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000178 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000179 switch (copy->GetElementsKind()) {
180 case JSObject::FAST_ELEMENTS: {
181 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 if (elements->map() == heap->fixed_cow_array_map()) {
183 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000184#ifdef DEBUG
185 for (int i = 0; i < elements->length(); i++) {
186 ASSERT(!elements->get(i)->IsJSObject());
187 }
188#endif
189 } else {
190 for (int i = 0; i < elements->length(); i++) {
191 Object* value = elements->get(i);
192 if (value->IsJSObject()) {
193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
195 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000198 elements->set(i, result);
199 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 case JSObject::DICTIONARY_ELEMENTS: {
205 NumberDictionary* element_dictionary = copy->element_dictionary();
206 int capacity = element_dictionary->Capacity();
207 for (int i = 0; i < capacity; i++) {
208 Object* k = element_dictionary->KeyAt(i);
209 if (element_dictionary->IsKey(k)) {
210 Object* value = element_dictionary->ValueAt(i);
211 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
214 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 element_dictionary->ValueAtPut(i, result);
218 }
219 }
220 }
221 break;
222 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000223 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
224 UNIMPLEMENTED();
225 break;
226 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
227 case JSObject::EXTERNAL_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
229 case JSObject::EXTERNAL_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
231 case JSObject::EXTERNAL_INT_ELEMENTS:
232 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
233 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
234 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
235 case JSObject::FAST_DOUBLE_ELEMENTS:
236 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
239 return copy;
240}
241
242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000243RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000249RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252}
253
254
ager@chromium.org236ad962008-09-25 09:45:57 +0000255static Handle<Map> ComputeObjectLiteralMap(
256 Handle<Context> context,
257 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000260 int properties_length = constant_properties->length();
261 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 for (int p = 0; p != properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 uint32_t element_index = 0;
268 if (key->IsSymbol()) {
269 number_of_symbol_keys++;
270 } else if (key->ToArrayIndex(&element_index)) {
271 // An index key does not require space in the property backing store.
272 number_of_properties--;
273 } else {
274 // Bail out as a non-symbol non-index key makes caching impossible.
275 // ASSERT to make sure that the if condition after the loop is false.
276 ASSERT(number_of_symbol_keys != number_of_properties);
277 break;
278 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 // If we only have symbols and array indices among keys then we can
281 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 if ((number_of_symbol_keys == number_of_properties) &&
284 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Handle<FixedArray> keys =
287 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 if (number_of_symbol_keys > 0) {
289 int index = 0;
290 for (int p = 0; p < properties_length; p += 2) {
291 Object* key = constant_properties->get(p);
292 if (key->IsSymbol()) {
293 keys->set(index++, key);
294 }
295 }
296 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
301 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000302 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000304 Handle<Map>(context->object_function()->initial_map()),
305 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000306}
307
308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 Handle<FixedArray> literals,
312 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314
315static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 bool should_have_fast_elements,
320 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 // Get the global context from the literals array. This is the
322 // context in which the function was created and we use the object
323 // function from this context to create the object literal. We do
324 // not use the object function from the current global context
325 // because this might be the object function from another context
326 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000327 Handle<Context> context =
328 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // In case we have function literals, we want the object to be in
331 // slow properties mode for now. We don't go in the map cache because
332 // maps with constant functions can't be shared if the functions are
333 // not the same (which is the common case).
334 bool is_result_from_cache = false;
335 Handle<Map> map = has_function_literal
336 ? Handle<Map>(context->object_function()->initial_map())
337 : ComputeObjectLiteralMap(context,
338 constant_properties,
339 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 // Normalize the elements of the boilerplate to save space if needed.
344 if (!should_have_fast_elements) NormalizeElements(boilerplate);
345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 // Add the constant properties to the boilerplate.
347 int length = constant_properties->length();
348 bool should_transform =
349 !is_result_from_cache && boilerplate->HasFastProperties();
350 if (should_transform || has_function_literal) {
351 // Normalize the properties of object to avoid n^2 behavior
352 // when extending the object multiple properties. Indicate the number of
353 // properties to be added.
354 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
355 }
356
357 for (int index = 0; index < length; index +=2) {
358 Handle<Object> key(constant_properties->get(index+0), isolate);
359 Handle<Object> value(constant_properties->get(index+1), isolate);
360 if (value->IsFixedArray()) {
361 // The value contains the constant_properties of a
362 // simple object or array literal.
363 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
364 value = CreateLiteralBoilerplate(isolate, literals, array);
365 if (value.is_null()) return value;
366 }
367 Handle<Object> result;
368 uint32_t element_index = 0;
369 if (key->IsSymbol()) {
370 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
371 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 Handle<String> name(String::cast(*key));
378 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000379 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
380 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 } else if (key->ToArrayIndex(&element_index)) {
383 // Array index (uint32).
384 result = SetOwnElement(boilerplate,
385 element_index,
386 value,
387 kNonStrictMode);
388 } else {
389 // Non-uint32 number.
390 ASSERT(key->IsNumber());
391 double num = key->Number();
392 char arr[100];
393 Vector<char> buffer(arr, ARRAY_SIZE(arr));
394 const char* str = DoubleToCString(num, buffer);
395 Handle<String> name =
396 isolate->factory()->NewStringFromAscii(CStrVector(str));
397 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
398 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 // If setting the property on the boilerplate throws an
401 // exception, the exception is converted to an empty handle in
402 // the handle based operations. In that case, we need to
403 // convert back to an exception.
404 if (result.is_null()) return result;
405 }
406
407 // Transform to fast properties if necessary. For object literals with
408 // containing function literals we defer this operation until after all
409 // computed properties have been assigned so that we can generate
410 // constant function properties.
411 if (should_transform && !has_function_literal) {
412 TransformToFastProperties(boilerplate,
413 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417}
418
419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000422 Handle<FixedArray> literals,
423 Handle<FixedArray> elements) {
424 // Create the JSArray.
425 Handle<JSFunction> constructor(
426 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 const bool is_cow =
430 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
434 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (is_cow) {
436#ifdef DEBUG
437 // Copy-on-write arrays must be shallow (and simple).
438 for (int i = 0; i < content->length(); i++) {
439 ASSERT(!content->get(i)->IsFixedArray());
440 }
441#endif
442 } else {
443 for (int i = 0; i < content->length(); i++) {
444 if (content->get(i)->IsFixedArray()) {
445 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000447 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
448 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000450 if (result.is_null()) return result;
451 content->set(i, *result);
452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 }
454 }
455
456 // Set the elements.
457 Handle<JSArray>::cast(object)->SetContent(*content);
458 return object;
459}
460
461
462static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000464 Handle<FixedArray> literals,
465 Handle<FixedArray> array) {
466 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateObjectLiteralBoilerplate(isolate,
471 literals,
472 elements,
473 true,
474 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 return CreateObjectLiteralBoilerplate(isolate,
477 literals,
478 elements,
479 false,
480 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 default:
484 UNREACHABLE();
485 return Handle<Object>::null();
486 }
487}
488
489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000490RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 // Takes a FixedArray of elements containing the literal elements of
492 // the array literal and produces JSArray with those elements.
493 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494 // which contains the context from which to get the Array function
495 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000497 ASSERT(args.length() == 3);
498 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000499 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000500 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 Handle<Object> object =
503 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 // Update the functions literal and return the boilerplate.
507 literals->set(literals_index, *object);
508 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000516 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000518 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
520 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521
522 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 Handle<Object> boilerplate(literals->get(literals_index), isolate);
524 if (*boilerplate == isolate->heap()->undefined_value()) {
525 boilerplate = CreateObjectLiteralBoilerplate(isolate,
526 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 should_have_fast_elements,
529 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 if (boilerplate.is_null()) return Failure::Exception();
531 // Update the functions literal and return the boilerplate.
532 literals->set(literals_index, *boilerplate);
533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000542 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
546 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<Object> boilerplate(literals->get(literals_index), isolate);
550 if (*boilerplate == isolate->heap()->undefined_value()) {
551 boilerplate = CreateObjectLiteralBoilerplate(isolate,
552 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 should_have_fast_elements,
555 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 if (boilerplate.is_null()) return Failure::Exception();
557 // Update the functions literal and return the boilerplate.
558 literals->set(literals_index, *boilerplate);
559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561}
562
563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000564RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566 ASSERT(args.length() == 3);
567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000568 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
570
571 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<Object> boilerplate(literals->get(literals_index), isolate);
573 if (*boilerplate == isolate->heap()->undefined_value()) {
574 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 if (boilerplate.is_null()) return Failure::Exception();
576 // Update the functions literal and return the boilerplate.
577 literals->set(literals_index, *boilerplate);
578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580}
581
582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000583RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 ASSERT(args.length() == 3);
586 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000587 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
589
590 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 Handle<Object> boilerplate(literals->get(literals_index), isolate);
592 if (*boilerplate == isolate->heap()->undefined_value()) {
593 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594 if (boilerplate.is_null()) return Failure::Exception();
595 // Update the functions literal and return the boilerplate.
596 literals->set(literals_index, *boilerplate);
597 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000598 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000600 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
607 ASSERT(args.length() == 2);
608 Object* handler = args[0];
609 Object* prototype = args[1];
610 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000611 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000612 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
613}
614
615
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000616RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
639 HandleScope scope(isolate);
640 ASSERT(args.length() == 1);
641 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
642 ASSERT(weakmap->map()->inobject_properties() == 0);
643 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
644 weakmap->set_table(*table);
645 weakmap->set_next(Smi::FromInt(0));
646 return *weakmap;
647}
648
649
650RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
651 NoHandleAllocation ha;
652 ASSERT(args.length() == 2);
653 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
654 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
655 // because they cannot be cast to JSObject to get an identity hash code.
656 CONVERT_ARG_CHECKED(JSObject, key, 1);
657 return weakmap->table()->Lookup(*key);
658}
659
660
661RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
662 HandleScope scope(isolate);
663 ASSERT(args.length() == 3);
664 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
665 // TODO(mstarzinger): See Runtime_WeakMapGet above.
666 CONVERT_ARG_CHECKED(JSObject, key, 1);
667 Handle<Object> value(args[2]);
668 Handle<ObjectHashTable> table(weakmap->table());
669 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
670 weakmap->set_table(*new_table);
671 return *value;
672}
673
674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 return JSObject::cast(obj)->class_name();
681}
682
ager@chromium.org7c537e22008-10-16 08:43:32 +0000683
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
685 NoHandleAllocation ha;
686 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000687 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
688 Object* obj = input_obj;
689 // We don't expect access checks to be needed on JSProxy objects.
690 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000692 if (obj->IsAccessCheckNeeded() &&
693 !isolate->MayNamedAccess(JSObject::cast(obj),
694 isolate->heap()->Proto_symbol(),
695 v8::ACCESS_GET)) {
696 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
697 return isolate->heap()->undefined_value();
698 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000699 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000700 } while (obj->IsJSObject() &&
701 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000702 return obj;
703}
704
705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000706RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 NoHandleAllocation ha;
708 ASSERT(args.length() == 2);
709 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
710 Object* O = args[0];
711 Object* V = args[1];
712 while (true) {
713 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 if (prototype->IsNull()) return isolate->heap()->false_value();
715 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 V = prototype;
717 }
718}
719
720
ager@chromium.org9085a012009-05-11 19:22:57 +0000721// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000723 NoHandleAllocation ha;
724 ASSERT(args.length() == 2);
725 CONVERT_CHECKED(JSObject, jsobject, args[0]);
726 CONVERT_CHECKED(JSObject, proto, args[1]);
727
728 // Sanity checks. The old prototype (that we are replacing) could
729 // theoretically be null, but if it is not null then check that we
730 // didn't already install a hidden prototype here.
731 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
732 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
733 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
734
735 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000736 Object* map_or_failure;
737 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
738 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
739 return maybe_map_or_failure;
740 }
741 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000742 Map* new_proto_map = Map::cast(map_or_failure);
743
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
745 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
746 return maybe_map_or_failure;
747 }
748 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000749 Map* new_map = Map::cast(map_or_failure);
750
751 // Set proto's prototype to be the old prototype of the object.
752 new_proto_map->set_prototype(jsobject->GetPrototype());
753 proto->set_map(new_proto_map);
754 new_proto_map->set_is_hidden_prototype();
755
756 // Set the object's prototype to proto.
757 new_map->set_prototype(proto);
758 jsobject->set_map(new_map);
759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000760 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000761}
762
763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000764RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000766 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000767 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769}
770
771
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000772// Recursively traverses hidden prototypes if property is not found
773static void GetOwnPropertyImplementation(JSObject* obj,
774 String* name,
775 LookupResult* result) {
776 obj->LocalLookupRealNamedProperty(name, result);
777
778 if (!result->IsProperty()) {
779 Object* proto = obj->GetPrototype();
780 if (proto->IsJSObject() &&
781 JSObject::cast(proto)->map()->is_hidden_prototype())
782 GetOwnPropertyImplementation(JSObject::cast(proto),
783 name, result);
784 }
785}
786
787
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788static bool CheckAccessException(LookupResult* result,
789 v8::AccessType access_type) {
790 if (result->type() == CALLBACKS) {
791 Object* callback = result->GetCallbackObject();
792 if (callback->IsAccessorInfo()) {
793 AccessorInfo* info = AccessorInfo::cast(callback);
794 bool can_access =
795 (access_type == v8::ACCESS_HAS &&
796 (info->all_can_read() || info->all_can_write())) ||
797 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
798 (access_type == v8::ACCESS_SET && info->all_can_write());
799 return can_access;
800 }
801 }
802
803 return false;
804}
805
806
807static bool CheckAccess(JSObject* obj,
808 String* name,
809 LookupResult* result,
810 v8::AccessType access_type) {
811 ASSERT(result->IsProperty());
812
813 JSObject* holder = result->holder();
814 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000816 while (true) {
817 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 // Access check callback denied the access, but some properties
820 // can have a special permissions which override callbacks descision
821 // (currently see v8::AccessControl).
822 break;
823 }
824
825 if (current == holder) {
826 return true;
827 }
828
829 current = JSObject::cast(current->GetPrototype());
830 }
831
832 // API callbacks can have per callback access exceptions.
833 switch (result->type()) {
834 case CALLBACKS: {
835 if (CheckAccessException(result, access_type)) {
836 return true;
837 }
838 break;
839 }
840 case INTERCEPTOR: {
841 // If the object has an interceptor, try real named properties.
842 // Overwrite the result to fetch the correct property later.
843 holder->LookupRealNamedProperty(name, result);
844 if (result->IsProperty()) {
845 if (CheckAccessException(result, access_type)) {
846 return true;
847 }
848 }
849 break;
850 }
851 default:
852 break;
853 }
854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 return false;
857}
858
859
860// TODO(1095): we should traverse hidden prototype hierachy as well.
861static bool CheckElementAccess(JSObject* obj,
862 uint32_t index,
863 v8::AccessType access_type) {
864 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000866 return false;
867 }
868
869 return true;
870}
871
872
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000873// Enumerator used as indices into the array returned from GetOwnProperty
874enum PropertyDescriptorIndices {
875 IS_ACCESSOR_INDEX,
876 VALUE_INDEX,
877 GETTER_INDEX,
878 SETTER_INDEX,
879 WRITABLE_INDEX,
880 ENUMERABLE_INDEX,
881 CONFIGURABLE_INDEX,
882 DESCRIPTOR_SIZE
883};
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Returns an array with the property description:
886// if args[1] is not a property on args[0]
887// returns undefined
888// if args[1] is a data property on args[0]
889// [false, value, Writeable, Enumerable, Configurable]
890// if args[1] is an accessor on args[0]
891// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = isolate->heap();
895 HandleScope scope(isolate);
896 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
897 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000898 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000899 CONVERT_ARG_CHECKED(JSObject, obj, 0);
900 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000902 // This could be an element.
903 uint32_t index;
904 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 switch (obj->HasLocalElement(index)) {
906 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 case JSObject::STRING_CHARACTER_ELEMENT: {
910 // Special handling of string objects according to ECMAScript 5
911 // 15.5.5.2. Note that this might be a string object with elements
912 // other than the actual string value. This is covered by the
913 // subsequent cases.
914 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
915 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(WRITABLE_INDEX, heap->false_value());
921 elms->set(ENUMERABLE_INDEX, heap->false_value());
922 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 return *desc;
924 }
925
926 case JSObject::INTERCEPTED_ELEMENT:
927 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000929 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 elms->set(WRITABLE_INDEX, heap->true_value());
933 elms->set(ENUMERABLE_INDEX, heap->true_value());
934 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000935 return *desc;
936 }
937
938 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000939 Handle<JSObject> holder = obj;
940 if (obj->IsJSGlobalProxy()) {
941 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943 ASSERT(proto->IsJSGlobalObject());
944 holder = Handle<JSObject>(JSObject::cast(proto));
945 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000946 FixedArray* elements = FixedArray::cast(holder->elements());
947 NumberDictionary* dictionary = NULL;
948 if (elements->map() == heap->non_strict_arguments_elements_map()) {
949 dictionary = NumberDictionary::cast(elements->get(1));
950 } else {
951 dictionary = NumberDictionary::cast(elements);
952 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000953 int entry = dictionary->FindEntry(index);
954 ASSERT(entry != NumberDictionary::kNotFound);
955 PropertyDetails details = dictionary->DetailsAt(entry);
956 switch (details.type()) {
957 case CALLBACKS: {
958 // This is an accessor property with getter and/or setter.
959 FixedArray* callbacks =
960 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
963 elms->set(GETTER_INDEX, callbacks->get(0));
964 }
965 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
966 elms->set(SETTER_INDEX, callbacks->get(1));
967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 break;
969 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000970 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000973 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000974 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000975 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000977 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000978 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000979 default:
980 UNREACHABLE();
981 break;
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
984 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 return *desc;
986 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987 }
988 }
989
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000990 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000991 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000992
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000993 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000996
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000997 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999 }
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1002 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001003
1004 bool is_js_accessor = (result.type() == CALLBACKS) &&
1005 (result.GetCallbackObject()->IsFixedArray());
1006
1007 if (is_js_accessor) {
1008 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001010
1011 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1012 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1013 elms->set(GETTER_INDEX, structure->get(0));
1014 }
1015 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1016 elms->set(SETTER_INDEX, structure->get(1));
1017 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001018 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1020 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001021
1022 PropertyAttributes attrs;
1023 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001024 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001025 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1026 if (!maybe_value->ToObject(&value)) return maybe_value;
1027 }
1028 elms->set(VALUE_INDEX, value);
1029 }
1030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001031 return *desc;
1032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(JSObject, obj, args[0]);
1038 return obj->PreventExtensions();
1039}
1040
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001042RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001043 ASSERT(args.length() == 1);
1044 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 obj = JSObject::cast(proto);
1050 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001051 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001058 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1059 CONVERT_ARG_CHECKED(String, pattern, 1);
1060 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001061 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1062 if (result.is_null()) return Failure::Exception();
1063 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001067RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001070 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 ASSERT(args.length() == 1);
1077 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001078 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080}
1081
1082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 ASSERT(args.length() == 2);
1085 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001087 int index = field->value();
1088 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1089 InstanceType type = templ->map()->instance_type();
1090 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1091 type == OBJECT_TEMPLATE_INFO_TYPE);
1092 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001094 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1095 } else {
1096 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1097 }
1098 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001102RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001103 ASSERT(args.length() == 1);
1104 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001105 Map* old_map = object->map();
1106 bool needs_access_checks = old_map->is_access_check_needed();
1107 if (needs_access_checks) {
1108 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001109 Object* new_map;
1110 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1111 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1112 }
ager@chromium.org32912102009-01-16 10:38:43 +00001113
1114 Map::cast(new_map)->set_is_access_check_needed(false);
1115 object->set_map(Map::cast(new_map));
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001122 ASSERT(args.length() == 1);
1123 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001124 Map* old_map = object->map();
1125 if (!old_map->is_access_check_needed()) {
1126 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001127 Object* new_map;
1128 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1129 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1130 }
ager@chromium.org32912102009-01-16 10:38:43 +00001131
1132 Map::cast(new_map)->set_is_access_check_needed(true);
1133 object->set_map(Map::cast(new_map));
1134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001135 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001136}
1137
1138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001139static Failure* ThrowRedeclarationError(Isolate* isolate,
1140 const char* type,
1141 Handle<String> name) {
1142 HandleScope scope(isolate);
1143 Handle<Object> type_handle =
1144 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 Handle<Object> args[2] = { type_handle, name };
1146 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1148 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149}
1150
1151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001152RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001153 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 HandleScope scope(isolate);
1155 Handle<GlobalObject> global = Handle<GlobalObject>(
1156 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157
ager@chromium.org3811b432009-10-28 14:53:37 +00001158 Handle<Context> context = args.at<Context>(0);
1159 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001160 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 // Traverse the name/value pairs and set the properties.
1163 int length = pairs->length();
1164 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169 // We have to declare a global const property. To capture we only
1170 // assign to it when evaluating the assignment for "const x =
1171 // <expr>" the initial value is the hole.
1172 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001173 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 if (value->IsUndefined() || is_const_property) {
1175 // Lookup the property in the global object, and don't set the
1176 // value of the variable if the property is already there.
1177 LookupResult lookup;
1178 global->Lookup(*name, &lookup);
1179 if (lookup.IsProperty()) {
1180 // Determine if the property is local by comparing the holder
1181 // against the global object. The information will be used to
1182 // avoid throwing re-declaration errors when declaring
1183 // variables or constants that exist in the prototype chain.
1184 bool is_local = (*global == lookup.holder());
1185 // Get the property attributes and determine if the property is
1186 // read-only.
1187 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1188 bool is_read_only = (attributes & READ_ONLY) != 0;
1189 if (lookup.type() == INTERCEPTOR) {
1190 // If the interceptor says the property is there, we
1191 // just return undefined without overwriting the property.
1192 // Otherwise, we continue to setting the property.
1193 if (attributes != ABSENT) {
1194 // Check if the existing property conflicts with regards to const.
1195 if (is_local && (is_read_only || is_const_property)) {
1196 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001197 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 };
1199 // The property already exists without conflicting: Go to
1200 // the next declaration.
1201 continue;
1202 }
1203 // Fall-through and introduce the absent property by using
1204 // SetProperty.
1205 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001206 // For const properties, we treat a callback with this name
1207 // even in the prototype as a conflicting declaration.
1208 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001210 }
1211 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 if (is_local && (is_read_only || is_const_property)) {
1213 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 // The property already exists without conflicting: Go to
1217 // the next declaration.
1218 continue;
1219 }
1220 }
1221 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001222 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001224 Handle<SharedFunctionInfo> shared =
1225 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1228 context,
1229 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 value = function;
1231 }
1232
1233 LookupResult lookup;
1234 global->LocalLookup(*name, &lookup);
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001250 // Compute the property attributes. According to ECMA-262, section
1251 // 13, page 71, the property must be read-only and
1252 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1253 // property as read-only, so we don't either.
1254 int attr = NONE;
1255 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1256 attr |= DONT_DELETE;
1257 }
1258 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1259 if (is_const_property || (is_native && is_function_declaration)) {
1260 attr |= READ_ONLY;
1261 }
1262
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001263 // Safari does not allow the invocation of callback setters for
1264 // function declarations. To mimic this behavior, we do not allow
1265 // the invocation of setters for function values. This makes a
1266 // difference for global functions with the same names as event
1267 // handlers such as "function onload() {}". Firefox does call the
1268 // onload setter in those case and Safari does not. We follow
1269 // Safari for compatibility.
1270 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 // Do not change DONT_DELETE to false from true.
1272 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001274 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 RETURN_IF_EMPTY_HANDLE(isolate,
1278 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 name,
1280 value,
1281 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001283 StrictModeFlag strict_mode =
1284 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1285 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 RETURN_IF_EMPTY_HANDLE(isolate,
1287 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001288 name,
1289 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001290 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 }
1293 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 ASSERT(!isolate->has_pending_exception());
1296 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297}
1298
1299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001300RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 CONVERT_ARG_CHECKED(Context, context, 0);
1305 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001306 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001307 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001308 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001310 // Declarations are always done in a function or global context.
1311 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 int index;
1314 PropertyAttributes attributes;
1315 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001316 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001317 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001318 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 if (attributes != ABSENT) {
1321 // The name was declared before; check for conflicting
1322 // re-declarations: This is similar to the code in parser.cc in
1323 // the AstBuildingParser::Declare function.
1324 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1325 // Functions are not read-only.
1326 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1327 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001328 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
1330
1331 // Initialize it if necessary.
1332 if (*initial_value != NULL) {
1333 if (index >= 0) {
1334 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 // the function context or the arguments object.
1336 if (holder->IsContext()) {
1337 ASSERT(holder.is_identical_to(context));
1338 if (((attributes & READ_ONLY) == 0) ||
1339 context->get(index)->IsTheHole()) {
1340 context->set(index, *initial_value);
1341 }
1342 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001343 // The holder is an arguments object.
1344 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 Handle<Object> result = SetElement(arguments, index, initial_value,
1346 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001347 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 } else {
1350 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001351 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001352 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001354 SetProperty(context_ext, name, initial_value,
1355 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001360 // The property is not in the function context. It needs to be
1361 // "declared" in the function context's extension context, or in the
1362 // global context.
1363 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001364 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 } else {
1368 // The function context's extension context does not exists - allocate
1369 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 context_ext = isolate->factory()->NewJSObject(
1371 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 // And store it in the extension slot.
1373 context->set_extension(*context_ext);
1374 }
1375 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 // Declare the property by setting it to the initial value if provided,
1378 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1379 // constant declarations).
1380 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001383 // Declaring a const context slot is a conflicting declaration if
1384 // there is a callback with that name in a prototype. It is
1385 // allowed to introduce const variables in
1386 // JSContextExtensionObjects. They are treated specially in
1387 // SetProperty and no setters are invoked for those since they are
1388 // not real JSObjects.
1389 if (initial_value->IsTheHole() &&
1390 !context_ext->IsJSContextExtensionObject()) {
1391 LookupResult lookup;
1392 context_ext->Lookup(*name, &lookup);
1393 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001395 }
1396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 RETURN_IF_EMPTY_HANDLE(isolate,
1398 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001399 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403}
1404
1405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001406RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 // args[0] == name
1409 // args[1] == strict_mode
1410 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 // Determine if we need to assign to the variable if it already
1413 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1415 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
1417 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001420 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // According to ECMA-262, section 12.2, page 62, the property must
1424 // not be deletable.
1425 PropertyAttributes attributes = DONT_DELETE;
1426
1427 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 // there, there is a property with this name in the prototype chain.
1429 // We follow Safari and Firefox behavior and only set the property
1430 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001431 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001432 // Note that objects can have hidden prototypes, so we need to traverse
1433 // the whole chain of hidden prototypes to do a 'local' lookup.
1434 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001436 while (true) {
1437 real_holder->LocalLookup(*name, &lookup);
1438 if (lookup.IsProperty()) {
1439 // Determine if this is a redeclaration of something read-only.
1440 if (lookup.IsReadOnly()) {
1441 // If we found readonly property on one of hidden prototypes,
1442 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 if (real_holder != isolate->context()->global()) break;
1444 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001445 }
1446
1447 // Determine if this is a redeclaration of an intercepted read-only
1448 // property and figure out if the property exists at all.
1449 bool found = true;
1450 PropertyType type = lookup.type();
1451 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001453 Handle<JSObject> holder(real_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 real_holder = *holder;
1456 if (intercepted == ABSENT) {
1457 // The interceptor claims the property isn't there. We need to
1458 // make sure to introduce it.
1459 found = false;
1460 } else if ((intercepted & READ_ONLY) != 0) {
1461 // The property is present, but read-only. Since we're trying to
1462 // overwrite it with a variable declaration we must throw a
1463 // re-declaration error. However if we found readonly property
1464 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 if (real_holder != isolate->context()->global()) break;
1466 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001467 }
1468 }
1469
1470 if (found && !assign) {
1471 // The global property is there and we're not assigning any value
1472 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001474 }
1475
1476 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 return real_holder->SetProperty(
1479 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001480 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001481
1482 Object* proto = real_holder->GetPrototype();
1483 if (!proto->IsJSObject())
1484 break;
1485
1486 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1487 break;
1488
1489 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493 if (assign) {
1494 return global->SetProperty(*name, args[2], attributes, strict_mode);
1495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 // All constants are declared with an initial value. The name
1502 // of the constant is the first argument and the initial value
1503 // is the second.
1504 RUNTIME_ASSERT(args.length() == 2);
1505 CONVERT_ARG_CHECKED(String, name, 0);
1506 Handle<Object> value = args.at<Object>(1);
1507
1508 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
1511 // According to ECMA-262, section 12.2, page 62, the property must
1512 // not be deletable. Since it's a const, it must be READ_ONLY too.
1513 PropertyAttributes attributes =
1514 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1515
1516 // Lookup the property locally in the global object. If it isn't
1517 // there, we add the property and take special precautions to always
1518 // add it as a local property even in case of callbacks in the
1519 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001520 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 LookupResult lookup;
1522 global->LocalLookup(*name, &lookup);
1523 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001524 return global->SetLocalPropertyIgnoreAttributes(*name,
1525 *value,
1526 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 // Determine if this is a redeclaration of something not
1530 // read-only. In case the result is hidden behind an interceptor we
1531 // need to ask it for the property attributes.
1532 if (!lookup.IsReadOnly()) {
1533 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536
1537 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1538
1539 // Throw re-declaration error if the intercepted property is present
1540 // but not read-only.
1541 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 }
1544
1545 // Restore global object from context (in case of GC) and continue
1546 // with setting the value because the property is either absent or
1547 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 HandleScope handle_scope(isolate);
1549 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001551 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 // property through an interceptor and only do it if it's
1553 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001554 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 RETURN_IF_EMPTY_HANDLE(isolate,
1556 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001557 name,
1558 value,
1559 attributes,
1560 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 return *value;
1562 }
1563
1564 // Set the value, but only we're assigning the initial value to a
1565 // constant. For now, we determine this by checking if the
1566 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001567 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 PropertyType type = lookup.type();
1569 if (type == FIELD) {
1570 FixedArray* properties = global->properties();
1571 int index = lookup.GetFieldIndex();
1572 if (properties->get(index)->IsTheHole()) {
1573 properties->set(index, *value);
1574 }
1575 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001576 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1577 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 }
1579 } else {
1580 // Ignore re-initialization of constants that have already been
1581 // assigned a function value.
1582 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1583 }
1584
1585 // Use the set value as the result of the operation.
1586 return *value;
1587}
1588
1589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001590RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 ASSERT(args.length() == 3);
1593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(!value->IsTheHole());
1596 CONVERT_ARG_CHECKED(Context, context, 1);
1597 Handle<String> name(String::cast(args[2]));
1598
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001599 // Initializations are always done in a function or global context.
1600 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
1602 int index;
1603 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001604 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001605 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001606 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001607 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // In most situations, the property introduced by the const
1610 // declaration should be present in the context extension object.
1611 // However, because declaration and initialization are separate, the
1612 // property might have been deleted (if it was introduced by eval)
1613 // before we reach the initialization point.
1614 //
1615 // Example:
1616 //
1617 // function f() { eval("delete x; const x;"); }
1618 //
1619 // In that case, the initialization behaves like a normal assignment
1620 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001623 // Property was found in a context. Perform the assignment if we
1624 // found some non-constant or an uninitialized constant.
1625 Handle<Context> context = Handle<Context>::cast(holder);
1626 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1627 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001628 }
1629 } else {
1630 // The holder is an arguments object.
1631 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001632 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001635 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 }
1637 return *value;
1638 }
1639
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 // The property could not be found, we introduce it in the global
1641 // context.
1642 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 Handle<JSObject> global = Handle<JSObject>(
1644 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001645 // Strict mode not needed (const disallowed in strict mode).
1646 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001647 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001648 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001649 return *value;
1650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 // The property was present in a context extension object.
1653 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 if (*context_ext == context->extension()) {
1656 // This is the property that was introduced by the const
1657 // declaration. Set it if it hasn't been set before. NOTE: We
1658 // cannot use GetProperty() to get the current value as it
1659 // 'unholes' the value.
1660 LookupResult lookup;
1661 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1662 ASSERT(lookup.IsProperty()); // the property was declared
1663 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1664
1665 PropertyType type = lookup.type();
1666 if (type == FIELD) {
1667 FixedArray* properties = context_ext->properties();
1668 int index = lookup.GetFieldIndex();
1669 if (properties->get(index)->IsTheHole()) {
1670 properties->set(index, *value);
1671 }
1672 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001673 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1674 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 }
1676 } else {
1677 // We should not reach here. Any real, named property should be
1678 // either a field or a dictionary slot.
1679 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
1681 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 // The property was found in a different context extension object.
1683 // Set it if it is not a read-only property.
1684 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001685 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001686 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001688 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 return *value;
1693}
1694
1695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001696RUNTIME_FUNCTION(MaybeObject*,
1697 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001699 ASSERT(args.length() == 2);
1700 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001701 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001702 if (object->HasFastProperties()) {
1703 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1704 }
1705 return *object;
1706}
1707
1708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001709RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001712 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1713 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001716 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001717 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001718 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001719 RUNTIME_ASSERT(index >= 0);
1720 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001722 Handle<Object> result = RegExpImpl::Exec(regexp,
1723 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001726 if (result.is_null()) return Failure::Exception();
1727 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001731RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001732 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001733 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001734 if (elements_count < 0 ||
1735 elements_count > FixedArray::kMaxLength ||
1736 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 Object* new_object;
1740 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1743 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1746 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1748 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001749 {
1750 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001752 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 }
1755 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 array->set_elements(elements);
1758 array->set_length(Smi::FromInt(elements_count));
1759 // Write in-object properties after the length of the array.
1760 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1761 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1762 return array;
1763}
1764
1765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001766RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767 AssertNoAllocation no_alloc;
1768 ASSERT(args.length() == 5);
1769 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1770 CONVERT_CHECKED(String, source, args[1]);
1771
1772 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001774
1775 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777
1778 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Map* map = regexp->map();
1782 Object* constructor = map->constructor();
1783 if (constructor->IsJSFunction() &&
1784 JSFunction::cast(constructor)->initial_map() == map) {
1785 // If we still have the original map, set in-object properties directly.
1786 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1787 // TODO(lrn): Consider skipping write barrier on booleans as well.
1788 // Both true and false should be in oldspace at all times.
1789 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1790 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1791 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1792 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1793 Smi::FromInt(0),
1794 SKIP_WRITE_BARRIER);
1795 return regexp;
1796 }
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799 PropertyAttributes final =
1800 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1801 PropertyAttributes writable =
1802 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001806 source,
1807 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001808 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001810 global,
1811 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 ASSERT(!result->IsFailure());
1813 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 ignoreCase,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 multiline,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
1822 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 Smi::FromInt(0),
1825 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001828 return regexp;
1829}
1830
1831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001832RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001834 ASSERT(args.length() == 1);
1835 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1836 // This is necessary to enable fast checks for absence of elements
1837 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 return Smi::FromInt(0);
1840}
1841
1842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1844 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001845 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001846 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1848 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1849 Handle<JSFunction> optimized =
1850 isolate->factory()->NewFunction(key,
1851 JS_OBJECT_TYPE,
1852 JSObject::kHeaderSize,
1853 code,
1854 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001855 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001856 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 return optimized;
1858}
1859
1860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 ASSERT(args.length() == 1);
1864 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1865
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001866 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1867 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1868 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1869 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1870 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1871 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1872 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873
1874 return *holder;
1875}
1876
1877
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1879 NoHandleAllocation handle_free;
1880 ASSERT(args.length() == 1);
1881 CONVERT_CHECKED(JSFunction, function, args[0]);
1882 SharedFunctionInfo* shared = function->shared();
1883 if (shared->native() || shared->strict_mode()) {
1884 return isolate->heap()->undefined_value();
1885 }
1886 // Returns undefined for strict or native functions, or
1887 // the associated global receiver for "normal" functions.
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001890 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001891 return global_context->global()->global_receiver();
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897 ASSERT(args.length() == 4);
1898 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001899 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 Handle<String> pattern = args.at<String>(2);
1901 Handle<String> flags = args.at<String>(3);
1902
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001903 // Get the RegExp function from the context in the literals array.
1904 // This is the RegExp function from the context in which the
1905 // function was created. We do not use the RegExp function from the
1906 // current global context because this might be the RegExp function
1907 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001908 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001909 Handle<JSFunction>(
1910 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 // Compute the regular expression literal.
1912 bool has_pending_exception;
1913 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1915 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 return Failure::Exception();
1919 }
1920 literals->set(index, *regexp);
1921 return *regexp;
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 return f->shared()->name();
1931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001935 NoHandleAllocation ha;
1936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, f, args[0]);
1939 CONVERT_CHECKED(String, name, args[1]);
1940 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001942}
1943
1944
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 1);
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 return isolate->heap()->ToBoolean(
1950 f->shared()->name_should_print_as_anonymous());
1951}
1952
1953
1954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1955 NoHandleAllocation ha;
1956 ASSERT(args.length() == 1);
1957 CONVERT_CHECKED(JSFunction, f, args[0]);
1958 f->shared()->set_name_should_print_as_anonymous(true);
1959 return isolate->heap()->undefined_value();
1960}
1961
1962
whesse@chromium.org7b260152011-06-20 15:33:18 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1964 HandleScope scope(isolate);
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
1968 fun->shared()->set_bound(true);
1969 return isolate->heap()->undefined_value();
1970}
1971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001972RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973 NoHandleAllocation ha;
1974 ASSERT(args.length() == 1);
1975
1976 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 Object* obj = f->RemovePrototype();
1978 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001981}
1982
1983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 1);
1987
1988 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1990 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991
1992 return *GetScriptWrapper(Handle<Script>::cast(script));
1993}
1994
1995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001996RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 NoHandleAllocation ha;
1998 ASSERT(args.length() == 1);
1999
2000 CONVERT_CHECKED(JSFunction, f, args[0]);
2001 return f->shared()->GetSourceCode();
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 NoHandleAllocation ha;
2007 ASSERT(args.length() == 1);
2008
2009 CONVERT_CHECKED(JSFunction, fun, args[0]);
2010 int pos = fun->shared()->start_position();
2011 return Smi::FromInt(pos);
2012}
2013
2014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002016 ASSERT(args.length() == 2);
2017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2020
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002021 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2022
2023 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002024 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 NoHandleAllocation ha;
2030 ASSERT(args.length() == 2);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
2033 CONVERT_CHECKED(String, name, args[1]);
2034 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 NoHandleAllocation ha;
2041 ASSERT(args.length() == 2);
2042
2043 CONVERT_CHECKED(JSFunction, fun, args[0]);
2044 CONVERT_CHECKED(Smi, length, args[1]);
2045 fun->shared()->set_length(length->value());
2046 return length;
2047}
2048
2049
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002050// Creates a local, readonly, property called length with the correct
2051// length (when read by the user). This effectively overwrites the
2052// interceptor used to normally provide the length.
2053RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2054 NoHandleAllocation ha;
2055 ASSERT(args.length() == 2);
2056 CONVERT_CHECKED(JSFunction, fun, args[0]);
2057 CONVERT_CHECKED(Smi, length, args[1]);
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062 PropertyAttributes attr =
2063 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2064 return fun->AddProperty(name, length, attr, kNonStrictMode);
2065}
2066
2067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002068RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002069 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 ASSERT(args.length() == 2);
2071
2072 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002073 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002074 Object* obj;
2075 { MaybeObject* maybe_obj =
2076 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2077 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079 return args[0]; // return TOS
2080}
2081
2082
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2084 NoHandleAllocation ha;
2085 RUNTIME_ASSERT(args.length() == 1);
2086 CONVERT_CHECKED(JSFunction, function, args[0]);
2087
2088 MaybeObject* maybe_name =
2089 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2090 String* name;
2091 if (!maybe_name->To(&name)) return maybe_name;
2092
2093 if (function->HasFastProperties()) {
2094 // Construct a new field descriptor with updated attributes.
2095 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2096 int index = instance_desc->Search(name);
2097 ASSERT(index != DescriptorArray::kNotFound);
2098 PropertyDetails details(instance_desc->GetDetails(index));
2099 CallbacksDescriptor new_desc(name,
2100 instance_desc->GetValue(index),
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.index());
2103 // Construct a new field descriptors array containing the new descriptor.
2104 Object* descriptors_unchecked;
2105 { MaybeObject* maybe_descriptors_unchecked =
2106 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2107 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2108 return maybe_descriptors_unchecked;
2109 }
2110 }
2111 DescriptorArray* new_descriptors =
2112 DescriptorArray::cast(descriptors_unchecked);
2113 // Create a new map featuring the new field descriptors array.
2114 Object* map_unchecked;
2115 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2116 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2117 return maybe_map_unchecked;
2118 }
2119 }
2120 Map* new_map = Map::cast(map_unchecked);
2121 new_map->set_instance_descriptors(new_descriptors);
2122 function->set_map(new_map);
2123 } else { // Dictionary properties.
2124 // Directly manipulate the property details.
2125 int entry = function->property_dictionary()->FindEntry(name);
2126 ASSERT(entry != StringDictionary::kNotFound);
2127 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2128 PropertyDetails new_details(
2129 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2130 details.type(),
2131 details.index());
2132 function->property_dictionary()->DetailsAtPut(entry, new_details);
2133 }
2134 return function;
2135}
2136
2137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144}
2145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002148 NoHandleAllocation ha;
2149 ASSERT(args.length() == 1);
2150
2151 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002152 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002153}
2154
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002156RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002157 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 ASSERT(args.length() == 2);
2160
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002161 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 Handle<Object> code = args.at<Object>(1);
2163
2164 Handle<Context> context(target->context());
2165
2166 if (!code->IsNull()) {
2167 RUNTIME_ASSERT(code->IsJSFunction());
2168 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170
2171 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 return Failure::Exception();
2173 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002174 // Since we don't store the source for this we should never
2175 // optimize this.
2176 shared->code()->set_optimizable(false);
2177
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002178 // Set the code, scope info, formal parameter count,
2179 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002180 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002186 // Set the source code of the target function to undefined.
2187 // SetCode is only used for built-in constructors like String,
2188 // Array, and Object, and some web code
2189 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002191 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002192 // Clear the optimization hints related to the compiled code as these are no
2193 // longer valid when the code is overwritten.
2194 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 context = Handle<Context>(fun->context());
2196
2197 // Make sure we get a fresh copy of the literal vector to avoid
2198 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002199 int number_of_literals = fun->NumberOfLiterals();
2200 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // Insert the object, regexp and array functions in the literals
2204 // array prefix. These are the functions that will be used when
2205 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002206 literals->set(JSFunction::kLiteralGlobalContextIndex,
2207 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 // It's okay to skip the write barrier here because the literals
2210 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002211 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 }
2214
2215 target->set_context(*context);
2216 return *target;
2217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 ASSERT(args.length() == 2);
2223 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002224 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 RUNTIME_ASSERT(num >= 0);
2226 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228}
2229
2230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2232 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002234 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237 }
2238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240}
2241
2242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
2247 CONVERT_CHECKED(String, subject, args[0]);
2248 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 uint32_t i = 0;
2252 if (index->IsSmi()) {
2253 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255 i = value;
2256 } else {
2257 ASSERT(index->IsHeapNumber());
2258 double value = HeapNumber::cast(index)->value();
2259 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261
2262 // Flatten the string. If someone wants to get a char at an index
2263 // in a cons string, it is likely that more indices will be
2264 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002265 Object* flat;
2266 { MaybeObject* maybe_flat = subject->TryFlatten();
2267 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2268 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 subject = String::cast(flat);
2270
2271 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 }
2274
2275 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002276}
2277
2278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002279RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285
2286class FixedArrayBuilder {
2287 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2289 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 length_(0) {
2291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(initial_capacity > 0);
2294 }
2295
2296 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2297 : array_(backing_store),
2298 length_(0) {
2299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
2326 ASSERT(length_ < capacity());
2327 array_->set(length_, value);
2328 length_++;
2329 }
2330
2331 void Add(Smi* value) {
2332 ASSERT(length_ < capacity());
2333 array_->set(length_, value);
2334 length_++;
2335 }
2336
2337 Handle<FixedArray> array() {
2338 return array_;
2339 }
2340
2341 int length() {
2342 return length_;
2343 }
2344
2345 int capacity() {
2346 return array_->length();
2347 }
2348
2349 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002350 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351 result_array->set_length(Smi::FromInt(length_));
2352 return result_array;
2353 }
2354
2355 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2356 target_array->set_elements(*array_);
2357 target_array->set_length(Smi::FromInt(length_));
2358 return target_array;
2359 }
2360
2361 private:
2362 Handle<FixedArray> array_;
2363 int length_;
2364};
2365
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368const int kStringBuilderConcatHelperLengthBits = 11;
2369const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370
2371template <typename schar>
2372static inline void StringBuilderConcatHelper(String*,
2373 schar*,
2374 FixedArray*,
2375 int);
2376
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2378 StringBuilderSubstringLength;
2379typedef BitField<int,
2380 kStringBuilderConcatHelperLengthBits,
2381 kStringBuilderConcatHelperPositionBits>
2382 StringBuilderSubstringPosition;
2383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384
2385class ReplacementStringBuilder {
2386 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002387 ReplacementStringBuilder(Heap* heap,
2388 Handle<String> subject,
2389 int estimated_part_count)
2390 : heap_(heap),
2391 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002394 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 // Require a non-zero initial size. Ensures that doubling the size to
2396 // extend the array will work.
2397 ASSERT(estimated_part_count > 0);
2398 }
2399
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2401 int from,
2402 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 ASSERT(from >= 0);
2404 int length = to - from;
2405 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 if (StringBuilderSubstringLength::is_valid(length) &&
2407 StringBuilderSubstringPosition::is_valid(from)) {
2408 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2409 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002412 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 builder->Add(Smi::FromInt(-length));
2414 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 }
2417
2418
2419 void EnsureCapacity(int elements) {
2420 array_builder_.EnsureCapacity(elements);
2421 }
2422
2423
2424 void AddSubjectSlice(int from, int to) {
2425 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429
2430 void AddString(Handle<String> string) {
2431 int length = string->length();
2432 ASSERT(length > 0);
2433 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002434 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 is_ascii_ = false;
2436 }
2437 IncrementCharacterCount(length);
2438 }
2439
2440
2441 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002443 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445
2446 Handle<String> joined_string;
2447 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 char* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 } else {
2457 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 uc16* char_buffer = seq->GetChars();
2461 StringBuilderConcatHelper(*subject_,
2462 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 *array_builder_.array(),
2464 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002465 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 }
2467 return joined_string;
2468 }
2469
2470
2471 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002472 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 V8::FatalProcessOutOfMemory("String.replace result too large.");
2474 }
2475 character_count_ += by;
2476 }
2477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002483 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2484 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 }
2486
2487
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2489 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491
2492
2493 void AddElement(Object* element) {
2494 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 ASSERT(array_builder_.capacity() > array_builder_.length());
2496 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 }
2498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002500 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002502 int character_count_;
2503 bool is_ascii_;
2504};
2505
2506
2507class CompiledReplacement {
2508 public:
2509 CompiledReplacement()
2510 : parts_(1), replacement_substrings_(0) {}
2511
2512 void Compile(Handle<String> replacement,
2513 int capture_count,
2514 int subject_length);
2515
2516 void Apply(ReplacementStringBuilder* builder,
2517 int match_from,
2518 int match_to,
2519 Handle<JSArray> last_match_info);
2520
2521 // Number of distinct parts of the replacement pattern.
2522 int parts() {
2523 return parts_.length();
2524 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002525
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 private:
2527 enum PartType {
2528 SUBJECT_PREFIX = 1,
2529 SUBJECT_SUFFIX,
2530 SUBJECT_CAPTURE,
2531 REPLACEMENT_SUBSTRING,
2532 REPLACEMENT_STRING,
2533
2534 NUMBER_OF_PART_TYPES
2535 };
2536
2537 struct ReplacementPart {
2538 static inline ReplacementPart SubjectMatch() {
2539 return ReplacementPart(SUBJECT_CAPTURE, 0);
2540 }
2541 static inline ReplacementPart SubjectCapture(int capture_index) {
2542 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2543 }
2544 static inline ReplacementPart SubjectPrefix() {
2545 return ReplacementPart(SUBJECT_PREFIX, 0);
2546 }
2547 static inline ReplacementPart SubjectSuffix(int subject_length) {
2548 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2549 }
2550 static inline ReplacementPart ReplacementString() {
2551 return ReplacementPart(REPLACEMENT_STRING, 0);
2552 }
2553 static inline ReplacementPart ReplacementSubString(int from, int to) {
2554 ASSERT(from >= 0);
2555 ASSERT(to > from);
2556 return ReplacementPart(-from, to);
2557 }
2558
2559 // If tag <= 0 then it is the negation of a start index of a substring of
2560 // the replacement pattern, otherwise it's a value from PartType.
2561 ReplacementPart(int tag, int data)
2562 : tag(tag), data(data) {
2563 // Must be non-positive or a PartType value.
2564 ASSERT(tag < NUMBER_OF_PART_TYPES);
2565 }
2566 // Either a value of PartType or a non-positive number that is
2567 // the negation of an index into the replacement string.
2568 int tag;
2569 // The data value's interpretation depends on the value of tag:
2570 // tag == SUBJECT_PREFIX ||
2571 // tag == SUBJECT_SUFFIX: data is unused.
2572 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2573 // tag == REPLACEMENT_SUBSTRING ||
2574 // tag == REPLACEMENT_STRING: data is index into array of substrings
2575 // of the replacement string.
2576 // tag <= 0: Temporary representation of the substring of the replacement
2577 // string ranging over -tag .. data.
2578 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2579 // substring objects.
2580 int data;
2581 };
2582
2583 template<typename Char>
2584 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2585 Vector<Char> characters,
2586 int capture_count,
2587 int subject_length) {
2588 int length = characters.length();
2589 int last = 0;
2590 for (int i = 0; i < length; i++) {
2591 Char c = characters[i];
2592 if (c == '$') {
2593 int next_index = i + 1;
2594 if (next_index == length) { // No next character!
2595 break;
2596 }
2597 Char c2 = characters[next_index];
2598 switch (c2) {
2599 case '$':
2600 if (i > last) {
2601 // There is a substring before. Include the first "$".
2602 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2603 last = next_index + 1; // Continue after the second "$".
2604 } else {
2605 // Let the next substring start with the second "$".
2606 last = next_index;
2607 }
2608 i = next_index;
2609 break;
2610 case '`':
2611 if (i > last) {
2612 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2613 }
2614 parts->Add(ReplacementPart::SubjectPrefix());
2615 i = next_index;
2616 last = i + 1;
2617 break;
2618 case '\'':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '&':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectMatch());
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '0':
2635 case '1':
2636 case '2':
2637 case '3':
2638 case '4':
2639 case '5':
2640 case '6':
2641 case '7':
2642 case '8':
2643 case '9': {
2644 int capture_ref = c2 - '0';
2645 if (capture_ref > capture_count) {
2646 i = next_index;
2647 continue;
2648 }
2649 int second_digit_index = next_index + 1;
2650 if (second_digit_index < length) {
2651 // Peek ahead to see if we have two digits.
2652 Char c3 = characters[second_digit_index];
2653 if ('0' <= c3 && c3 <= '9') { // Double digits.
2654 int double_digit_ref = capture_ref * 10 + c3 - '0';
2655 if (double_digit_ref <= capture_count) {
2656 next_index = second_digit_index;
2657 capture_ref = double_digit_ref;
2658 }
2659 }
2660 }
2661 if (capture_ref > 0) {
2662 if (i > last) {
2663 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2664 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002665 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2667 last = next_index + 1;
2668 }
2669 i = next_index;
2670 break;
2671 }
2672 default:
2673 i = next_index;
2674 break;
2675 }
2676 }
2677 }
2678 if (length > last) {
2679 if (last == 0) {
2680 parts->Add(ReplacementPart::ReplacementString());
2681 } else {
2682 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2683 }
2684 }
2685 }
2686
2687 ZoneList<ReplacementPart> parts_;
2688 ZoneList<Handle<String> > replacement_substrings_;
2689};
2690
2691
2692void CompiledReplacement::Compile(Handle<String> replacement,
2693 int capture_count,
2694 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002697 String::FlatContent content = replacement->GetFlatContent();
2698 ASSERT(content.IsFlat());
2699 if (content.IsAscii()) {
2700 ParseReplacementPattern(&parts_,
2701 content.ToAsciiVector(),
2702 capture_count,
2703 subject_length);
2704 } else {
2705 ASSERT(content.IsTwoByte());
2706 ParseReplacementPattern(&parts_,
2707 content.ToUC16Vector(),
2708 capture_count,
2709 subject_length);
2710 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002713 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 int substring_index = 0;
2715 for (int i = 0, n = parts_.length(); i < n; i++) {
2716 int tag = parts_[i].tag;
2717 if (tag <= 0) { // A replacement string slice.
2718 int from = -tag;
2719 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 replacement_substrings_.Add(
2721 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 parts_[i].tag = REPLACEMENT_SUBSTRING;
2723 parts_[i].data = substring_index;
2724 substring_index++;
2725 } else if (tag == REPLACEMENT_STRING) {
2726 replacement_substrings_.Add(replacement);
2727 parts_[i].data = substring_index;
2728 substring_index++;
2729 }
2730 }
2731}
2732
2733
2734void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2735 int match_from,
2736 int match_to,
2737 Handle<JSArray> last_match_info) {
2738 for (int i = 0, n = parts_.length(); i < n; i++) {
2739 ReplacementPart part = parts_[i];
2740 switch (part.tag) {
2741 case SUBJECT_PREFIX:
2742 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2743 break;
2744 case SUBJECT_SUFFIX: {
2745 int subject_length = part.data;
2746 if (match_to < subject_length) {
2747 builder->AddSubjectSlice(match_to, subject_length);
2748 }
2749 break;
2750 }
2751 case SUBJECT_CAPTURE: {
2752 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002753 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2755 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2756 if (from >= 0 && to > from) {
2757 builder->AddSubjectSlice(from, to);
2758 }
2759 break;
2760 }
2761 case REPLACEMENT_SUBSTRING:
2762 case REPLACEMENT_STRING:
2763 builder->AddString(replacement_substrings_[part.data]);
2764 break;
2765 default:
2766 UNREACHABLE();
2767 }
2768 }
2769}
2770
2771
2772
lrn@chromium.org303ada72010-10-27 09:33:13 +00002773MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002774 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002775 String* subject,
2776 JSRegExp* regexp,
2777 String* replacement,
2778 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002779 ASSERT(subject->IsFlat());
2780 ASSERT(replacement->IsFlat());
2781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002782 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002783
2784 int length = subject->length();
2785 Handle<String> subject_handle(subject);
2786 Handle<JSRegExp> regexp_handle(regexp);
2787 Handle<String> replacement_handle(replacement);
2788 Handle<JSArray> last_match_info_handle(last_match_info);
2789 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2790 subject_handle,
2791 0,
2792 last_match_info_handle);
2793 if (match.is_null()) {
2794 return Failure::Exception();
2795 }
2796 if (match->IsNull()) {
2797 return *subject_handle;
2798 }
2799
2800 int capture_count = regexp_handle->CaptureCount();
2801
2802 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002803 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002804 CompiledReplacement compiled_replacement;
2805 compiled_replacement.Compile(replacement_handle,
2806 capture_count,
2807 length);
2808
2809 bool is_global = regexp_handle->GetFlags().is_global();
2810
2811 // Guessing the number of parts that the final result string is built
2812 // from. Global regexps can match any number of times, so we guess
2813 // conservatively.
2814 int expected_parts =
2815 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002816 ReplacementStringBuilder builder(isolate->heap(),
2817 subject_handle,
2818 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002819
2820 // Index of end of last match.
2821 int prev = 0;
2822
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002823 // Number of parts added by compiled replacement plus preceeding
2824 // string and possibly suffix after last match. It is possible for
2825 // all components to use two elements when encoded as two smis.
2826 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002827 bool matched = true;
2828 do {
2829 ASSERT(last_match_info_handle->HasFastElements());
2830 // Increase the capacity of the builder before entering local handle-scope,
2831 // so its internal buffer can safely allocate a new handle if it grows.
2832 builder.EnsureCapacity(parts_added_per_loop);
2833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002834 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 int start, end;
2836 {
2837 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002838 FixedArray* match_info_array =
2839 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002840
2841 ASSERT_EQ(capture_count * 2 + 2,
2842 RegExpImpl::GetLastCaptureCount(match_info_array));
2843 start = RegExpImpl::GetCapture(match_info_array, 0);
2844 end = RegExpImpl::GetCapture(match_info_array, 1);
2845 }
2846
2847 if (prev < start) {
2848 builder.AddSubjectSlice(prev, start);
2849 }
2850 compiled_replacement.Apply(&builder,
2851 start,
2852 end,
2853 last_match_info_handle);
2854 prev = end;
2855
2856 // Only continue checking for global regexps.
2857 if (!is_global) break;
2858
2859 // Continue from where the match ended, unless it was an empty match.
2860 int next = end;
2861 if (start == end) {
2862 next = end + 1;
2863 if (next > length) break;
2864 }
2865
2866 match = RegExpImpl::Exec(regexp_handle,
2867 subject_handle,
2868 next,
2869 last_match_info_handle);
2870 if (match.is_null()) {
2871 return Failure::Exception();
2872 }
2873 matched = !match->IsNull();
2874 } while (matched);
2875
2876 if (prev < length) {
2877 builder.AddSubjectSlice(prev, length);
2878 }
2879
2880 return *(builder.ToString());
2881}
2882
2883
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002884template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002885MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002886 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002887 String* subject,
2888 JSRegExp* regexp,
2889 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002890 ASSERT(subject->IsFlat());
2891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002893
2894 Handle<String> subject_handle(subject);
2895 Handle<JSRegExp> regexp_handle(regexp);
2896 Handle<JSArray> last_match_info_handle(last_match_info);
2897 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2898 subject_handle,
2899 0,
2900 last_match_info_handle);
2901 if (match.is_null()) return Failure::Exception();
2902 if (match->IsNull()) return *subject_handle;
2903
2904 ASSERT(last_match_info_handle->HasFastElements());
2905
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002906 int start, end;
2907 {
2908 AssertNoAllocation match_info_array_is_not_in_a_handle;
2909 FixedArray* match_info_array =
2910 FixedArray::cast(last_match_info_handle->elements());
2911
2912 start = RegExpImpl::GetCapture(match_info_array, 0);
2913 end = RegExpImpl::GetCapture(match_info_array, 1);
2914 }
2915
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002916 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002917 int new_length = length - (end - start);
2918 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002920 }
2921 Handle<ResultSeqString> answer;
2922 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 answer = Handle<ResultSeqString>::cast(
2924 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002925 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 answer = Handle<ResultSeqString>::cast(
2927 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002928 }
2929
2930 // If the regexp isn't global, only match once.
2931 if (!regexp_handle->GetFlags().is_global()) {
2932 if (start > 0) {
2933 String::WriteToFlat(*subject_handle,
2934 answer->GetChars(),
2935 0,
2936 start);
2937 }
2938 if (end < length) {
2939 String::WriteToFlat(*subject_handle,
2940 answer->GetChars() + start,
2941 end,
2942 length);
2943 }
2944 return *answer;
2945 }
2946
2947 int prev = 0; // Index of end of last match.
2948 int next = 0; // Start of next search (prev unless last match was empty).
2949 int position = 0;
2950
2951 do {
2952 if (prev < start) {
2953 // Add substring subject[prev;start] to answer string.
2954 String::WriteToFlat(*subject_handle,
2955 answer->GetChars() + position,
2956 prev,
2957 start);
2958 position += start - prev;
2959 }
2960 prev = end;
2961 next = end;
2962 // Continue from where the match ended, unless it was an empty match.
2963 if (start == end) {
2964 next++;
2965 if (next > length) break;
2966 }
2967 match = RegExpImpl::Exec(regexp_handle,
2968 subject_handle,
2969 next,
2970 last_match_info_handle);
2971 if (match.is_null()) return Failure::Exception();
2972 if (match->IsNull()) break;
2973
2974 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002975 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002976 {
2977 AssertNoAllocation match_info_array_is_not_in_a_handle;
2978 FixedArray* match_info_array =
2979 FixedArray::cast(last_match_info_handle->elements());
2980 start = RegExpImpl::GetCapture(match_info_array, 0);
2981 end = RegExpImpl::GetCapture(match_info_array, 1);
2982 }
2983 } while (true);
2984
2985 if (prev < length) {
2986 // Add substring subject[prev;length] to answer string.
2987 String::WriteToFlat(*subject_handle,
2988 answer->GetChars() + position,
2989 prev,
2990 length);
2991 position += length - prev;
2992 }
2993
2994 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002995 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002996 }
2997
2998 // Shorten string and fill
2999 int string_size = ResultSeqString::SizeFor(position);
3000 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3001 int delta = allocated_string_size - string_size;
3002
3003 answer->set_length(position);
3004 if (delta == 0) return *answer;
3005
3006 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003007 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003008
3009 return *answer;
3010}
3011
3012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003013RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003014 ASSERT(args.length() == 4);
3015
3016 CONVERT_CHECKED(String, subject, args[0]);
3017 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003018 Object* flat_subject;
3019 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3020 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3021 return maybe_flat_subject;
3022 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003023 }
3024 subject = String::cast(flat_subject);
3025 }
3026
3027 CONVERT_CHECKED(String, replacement, args[2]);
3028 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003029 Object* flat_replacement;
3030 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3031 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3032 return maybe_flat_replacement;
3033 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034 }
3035 replacement = String::cast(flat_replacement);
3036 }
3037
3038 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3039 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3040
3041 ASSERT(last_match_info->HasFastElements());
3042
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003043 if (replacement->length() == 0) {
3044 if (subject->HasOnlyAsciiChars()) {
3045 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003046 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003047 } else {
3048 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003049 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003050 }
3051 }
3052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003053 return StringReplaceRegExpWithString(isolate,
3054 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003055 regexp,
3056 replacement,
3057 last_match_info);
3058}
3059
3060
ager@chromium.org7c537e22008-10-16 08:43:32 +00003061// Perform string match of pattern on subject, starting at start index.
3062// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003063// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003064int Runtime::StringMatch(Isolate* isolate,
3065 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003066 Handle<String> pat,
3067 int start_index) {
3068 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003069 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003070
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003071 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003072 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003075 if (start_index + pattern_length > subject_length) return -1;
3076
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003077 if (!sub->IsFlat()) FlattenString(sub);
3078 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003079
ager@chromium.org7c537e22008-10-16 08:43:32 +00003080 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003081 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003082 String::FlatContent seq_sub = sub->GetFlatContent();
3083 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003084
ager@chromium.org7c537e22008-10-16 08:43:32 +00003085 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003086 if (seq_pat.IsAscii()) {
3087 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3088 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003089 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003090 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 pat_vector,
3092 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003093 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003095 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 pat_vector,
3097 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003098 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003099 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3100 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003102 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003103 pat_vector,
3104 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003106 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003107 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 pat_vector,
3109 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003115 ASSERT(args.length() == 3);
3116
ager@chromium.org7c537e22008-10-16 08:43:32 +00003117 CONVERT_ARG_CHECKED(String, sub, 0);
3118 CONVERT_ARG_CHECKED(String, pat, 1);
3119
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003120 Object* index = args[2];
3121 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003122 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003123
ager@chromium.org870a0b62008-11-04 11:43:05 +00003124 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 int position =
3126 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003127 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128}
3129
3130
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003131template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003132static int StringMatchBackwards(Vector<const schar> subject,
3133 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003134 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003135 int pattern_length = pattern.length();
3136 ASSERT(pattern_length >= 1);
3137 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003138
3139 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003140 for (int i = 0; i < pattern_length; i++) {
3141 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003142 if (c > String::kMaxAsciiCharCode) {
3143 return -1;
3144 }
3145 }
3146 }
3147
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003148 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003149 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003150 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003151 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003152 while (j < pattern_length) {
3153 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003154 break;
3155 }
3156 j++;
3157 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003158 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003159 return i;
3160 }
3161 }
3162 return -1;
3163}
3164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003165RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003166 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003167 ASSERT(args.length() == 3);
3168
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003169 CONVERT_ARG_CHECKED(String, sub, 0);
3170 CONVERT_ARG_CHECKED(String, pat, 1);
3171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003173 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003174 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003176 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003177 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003178
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003179 if (start_index + pat_length > sub_length) {
3180 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003181 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003182
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003183 if (pat_length == 0) {
3184 return Smi::FromInt(start_index);
3185 }
3186
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003187 if (!sub->IsFlat()) FlattenString(sub);
3188 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003189
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003190 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003191 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3192
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003193 String::FlatContent sub_content = sub->GetFlatContent();
3194 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003195
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003196 if (pat_content.IsAscii()) {
3197 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3198 if (sub_content.IsAscii()) {
3199 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003200 pat_vector,
3201 start_index);
3202 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003203 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003204 pat_vector,
3205 start_index);
3206 }
3207 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003208 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3209 if (sub_content.IsAscii()) {
3210 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003211 pat_vector,
3212 start_index);
3213 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003214 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003215 pat_vector,
3216 start_index);
3217 }
3218 }
3219
3220 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003221}
3222
3223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225 NoHandleAllocation ha;
3226 ASSERT(args.length() == 2);
3227
3228 CONVERT_CHECKED(String, str1, args[0]);
3229 CONVERT_CHECKED(String, str2, args[1]);
3230
3231 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 int str1_length = str1->length();
3233 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003234
3235 // Decide trivial cases without flattening.
3236 if (str1_length == 0) {
3237 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3238 return Smi::FromInt(-str2_length);
3239 } else {
3240 if (str2_length == 0) return Smi::FromInt(str1_length);
3241 }
3242
3243 int end = str1_length < str2_length ? str1_length : str2_length;
3244
3245 // No need to flatten if we are going to find the answer on the first
3246 // character. At this point we know there is at least one character
3247 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003248 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249 if (d != 0) return Smi::FromInt(d);
3250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003251 str1->TryFlatten();
3252 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003254 StringInputBuffer& buf1 =
3255 *isolate->runtime_state()->string_locale_compare_buf1();
3256 StringInputBuffer& buf2 =
3257 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258
3259 buf1.Reset(str1);
3260 buf2.Reset(str2);
3261
3262 for (int i = 0; i < end; i++) {
3263 uint16_t char1 = buf1.GetNext();
3264 uint16_t char2 = buf2.GetNext();
3265 if (char1 != char2) return Smi::FromInt(char1 - char2);
3266 }
3267
3268 return Smi::FromInt(str1_length - str2_length);
3269}
3270
3271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003272RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003273 NoHandleAllocation ha;
3274 ASSERT(args.length() == 3);
3275
3276 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003277 int start, end;
3278 // We have a fast integer-only case here to avoid a conversion to double in
3279 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003280 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3281 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3282 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3283 start = from_number;
3284 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003285 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003286 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3287 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003288 start = FastD2I(from_number);
3289 end = FastD2I(to_number);
3290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 RUNTIME_ASSERT(end >= start);
3292 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003293 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003294 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003295 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296}
3297
3298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003300 ASSERT_EQ(3, args.length());
3301
3302 CONVERT_ARG_CHECKED(String, subject, 0);
3303 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3304 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3305 HandleScope handles;
3306
3307 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3308
3309 if (match.is_null()) {
3310 return Failure::Exception();
3311 }
3312 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003314 }
3315 int length = subject->length();
3316
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003317 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003318 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003319 int start;
3320 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003321 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003322 {
3323 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003324 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003325 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3326 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3327 }
3328 offsets.Add(start);
3329 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003330 if (start == end) if (++end > length) break;
3331 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003332 if (match.is_null()) {
3333 return Failure::Exception();
3334 }
3335 } while (!match->IsNull());
3336 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003338 Handle<String> substring = isolate->factory()->
3339 NewSubString(subject, offsets.at(0), offsets.at(1));
3340 elements->set(0, *substring);
3341 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003342 int from = offsets.at(i * 2);
3343 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003344 Handle<String> substring = isolate->factory()->
3345 NewProperSubString(subject, from, to);
3346 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003347 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003348 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003349 result->set_length(Smi::FromInt(matches));
3350 return *result;
3351}
3352
3353
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354// Two smis before and after the match, for very long strings.
3355const int kMaxBuilderEntriesPerRegExpMatch = 5;
3356
3357
3358static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3359 Handle<JSArray> last_match_info,
3360 int match_start,
3361 int match_end) {
3362 // Fill last_match_info with a single capture.
3363 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3364 AssertNoAllocation no_gc;
3365 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3366 RegExpImpl::SetLastCaptureCount(elements, 2);
3367 RegExpImpl::SetLastInput(elements, *subject);
3368 RegExpImpl::SetLastSubject(elements, *subject);
3369 RegExpImpl::SetCapture(elements, 0, match_start);
3370 RegExpImpl::SetCapture(elements, 1, match_end);
3371}
3372
3373
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003374template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375static bool SearchStringMultiple(Isolate* isolate,
3376 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003377 Vector<const PatternChar> pattern,
3378 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003379 FixedArrayBuilder* builder,
3380 int* match_pos) {
3381 int pos = *match_pos;
3382 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003383 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003386 while (pos <= max_search_start) {
3387 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3388 *match_pos = pos;
3389 return false;
3390 }
3391 // Position of end of previous match.
3392 int match_end = pos + pattern_length;
3393 int new_pos = search.Search(subject, match_end);
3394 if (new_pos >= 0) {
3395 // A match.
3396 if (new_pos > match_end) {
3397 ReplacementStringBuilder::AddSubjectSlice(builder,
3398 match_end,
3399 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003400 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003401 pos = new_pos;
3402 builder->Add(pattern_string);
3403 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003404 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003405 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003407
lrn@chromium.org25156de2010-04-06 13:10:27 +00003408 if (pos < max_search_start) {
3409 ReplacementStringBuilder::AddSubjectSlice(builder,
3410 pos + pattern_length,
3411 subject_length);
3412 }
3413 *match_pos = pos;
3414 return true;
3415}
3416
3417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003418static bool SearchStringMultiple(Isolate* isolate,
3419 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 Handle<String> pattern,
3421 Handle<JSArray> last_match_info,
3422 FixedArrayBuilder* builder) {
3423 ASSERT(subject->IsFlat());
3424 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003425
3426 // Treating as if a previous match was before first character.
3427 int match_pos = -pattern->length();
3428
3429 for (;;) { // Break when search complete.
3430 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3431 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003432 String::FlatContent subject_content = subject->GetFlatContent();
3433 String::FlatContent pattern_content = pattern->GetFlatContent();
3434 if (subject_content.IsAscii()) {
3435 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3436 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003437 if (SearchStringMultiple(isolate,
3438 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003439 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003440 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003441 builder,
3442 &match_pos)) break;
3443 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 if (SearchStringMultiple(isolate,
3445 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003446 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003447 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003448 builder,
3449 &match_pos)) break;
3450 }
3451 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003452 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3453 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 if (SearchStringMultiple(isolate,
3455 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003456 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003457 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003458 builder,
3459 &match_pos)) break;
3460 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003461 if (SearchStringMultiple(isolate,
3462 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003463 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003464 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003465 builder,
3466 &match_pos)) break;
3467 }
3468 }
3469 }
3470
3471 if (match_pos >= 0) {
3472 SetLastMatchInfoNoCaptures(subject,
3473 last_match_info,
3474 match_pos,
3475 match_pos + pattern->length());
3476 return true;
3477 }
3478 return false; // No matches at all.
3479}
3480
3481
3482static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 Handle<String> subject,
3485 Handle<JSRegExp> regexp,
3486 Handle<JSArray> last_match_array,
3487 FixedArrayBuilder* builder) {
3488 ASSERT(subject->IsFlat());
3489 int match_start = -1;
3490 int match_end = 0;
3491 int pos = 0;
3492 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3493 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3494
3495 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003496 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003497 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003498 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003499
3500 for (;;) { // Break on failure, return on exception.
3501 RegExpImpl::IrregexpResult result =
3502 RegExpImpl::IrregexpExecOnce(regexp,
3503 subject,
3504 pos,
3505 register_vector);
3506 if (result == RegExpImpl::RE_SUCCESS) {
3507 match_start = register_vector[0];
3508 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3509 if (match_end < match_start) {
3510 ReplacementStringBuilder::AddSubjectSlice(builder,
3511 match_end,
3512 match_start);
3513 }
3514 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003516 if (!first) {
3517 builder->Add(*isolate->factory()->NewProperSubString(subject,
3518 match_start,
3519 match_end));
3520 } else {
3521 builder->Add(*isolate->factory()->NewSubString(subject,
3522 match_start,
3523 match_end));
3524 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525 if (match_start != match_end) {
3526 pos = match_end;
3527 } else {
3528 pos = match_end + 1;
3529 if (pos > subject_length) break;
3530 }
3531 } else if (result == RegExpImpl::RE_FAILURE) {
3532 break;
3533 } else {
3534 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3535 return result;
3536 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003537 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538 }
3539
3540 if (match_start >= 0) {
3541 if (match_end < subject_length) {
3542 ReplacementStringBuilder::AddSubjectSlice(builder,
3543 match_end,
3544 subject_length);
3545 }
3546 SetLastMatchInfoNoCaptures(subject,
3547 last_match_array,
3548 match_start,
3549 match_end);
3550 return RegExpImpl::RE_SUCCESS;
3551 } else {
3552 return RegExpImpl::RE_FAILURE; // No matches at all.
3553 }
3554}
3555
3556
3557static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 Handle<String> subject,
3560 Handle<JSRegExp> regexp,
3561 Handle<JSArray> last_match_array,
3562 FixedArrayBuilder* builder) {
3563
3564 ASSERT(subject->IsFlat());
3565 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3566 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3567
3568 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003569 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003570
3571 RegExpImpl::IrregexpResult result =
3572 RegExpImpl::IrregexpExecOnce(regexp,
3573 subject,
3574 0,
3575 register_vector);
3576
3577 int capture_count = regexp->CaptureCount();
3578 int subject_length = subject->length();
3579
3580 // Position to search from.
3581 int pos = 0;
3582 // End of previous match. Differs from pos if match was empty.
3583 int match_end = 0;
3584 if (result == RegExpImpl::RE_SUCCESS) {
3585 // Need to keep a copy of the previous match for creating last_match_info
3586 // at the end, so we have two vectors that we swap between.
3587 OffsetsVector registers2(required_registers);
3588 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003589 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003590 do {
3591 int match_start = register_vector[0];
3592 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3593 if (match_end < match_start) {
3594 ReplacementStringBuilder::AddSubjectSlice(builder,
3595 match_end,
3596 match_start);
3597 }
3598 match_end = register_vector[1];
3599
3600 {
3601 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 // Arguments array to replace function is match, captures, index and
3604 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 Handle<FixedArray> elements =
3606 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 Handle<String> match;
3608 if (!first) {
3609 match = isolate->factory()->NewProperSubString(subject,
3610 match_start,
3611 match_end);
3612 } else {
3613 match = isolate->factory()->NewSubString(subject,
3614 match_start,
3615 match_end);
3616 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003617 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003618 for (int i = 1; i <= capture_count; i++) {
3619 int start = register_vector[i * 2];
3620 if (start >= 0) {
3621 int end = register_vector[i * 2 + 1];
3622 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring;
3624 if (!first) {
3625 substring = isolate->factory()->NewProperSubString(subject,
3626 start,
3627 end);
3628 } else {
3629 substring = isolate->factory()->NewSubString(subject, start, end);
3630 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003631 elements->set(i, *substring);
3632 } else {
3633 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635 }
3636 }
3637 elements->set(capture_count + 1, Smi::FromInt(match_start));
3638 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 }
3641 // Swap register vectors, so the last successful match is in
3642 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003643 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003644 prev_register_vector = register_vector;
3645 register_vector = tmp;
3646
3647 if (match_end > match_start) {
3648 pos = match_end;
3649 } else {
3650 pos = match_end + 1;
3651 if (pos > subject_length) {
3652 break;
3653 }
3654 }
3655
3656 result = RegExpImpl::IrregexpExecOnce(regexp,
3657 subject,
3658 pos,
3659 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003660 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003661 } while (result == RegExpImpl::RE_SUCCESS);
3662
3663 if (result != RegExpImpl::RE_EXCEPTION) {
3664 // Finished matching, with at least one match.
3665 if (match_end < subject_length) {
3666 ReplacementStringBuilder::AddSubjectSlice(builder,
3667 match_end,
3668 subject_length);
3669 }
3670
3671 int last_match_capture_count = (capture_count + 1) * 2;
3672 int last_match_array_size =
3673 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3674 last_match_array->EnsureSize(last_match_array_size);
3675 AssertNoAllocation no_gc;
3676 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3677 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3678 RegExpImpl::SetLastSubject(elements, *subject);
3679 RegExpImpl::SetLastInput(elements, *subject);
3680 for (int i = 0; i < last_match_capture_count; i++) {
3681 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3682 }
3683 return RegExpImpl::RE_SUCCESS;
3684 }
3685 }
3686 // No matches at all, return failure or exception result directly.
3687 return result;
3688}
3689
3690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003691RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694
3695 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003696 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003697 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3698 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3699 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3700
3701 ASSERT(last_match_info->HasFastElements());
3702 ASSERT(regexp->GetFlags().is_global());
3703 Handle<FixedArray> result_elements;
3704 if (result_array->HasFastElements()) {
3705 result_elements =
3706 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003707 }
3708 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 }
3711 FixedArrayBuilder builder(result_elements);
3712
3713 if (regexp->TypeTag() == JSRegExp::ATOM) {
3714 Handle<String> pattern(
3715 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003716 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003717 if (SearchStringMultiple(isolate, subject, pattern,
3718 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 return *builder.ToJSArray(result_array);
3720 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003721 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003722 }
3723
3724 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3725
3726 RegExpImpl::IrregexpResult result;
3727 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 result = SearchRegExpNoCaptureMultiple(isolate,
3729 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003730 regexp,
3731 last_match_info,
3732 &builder);
3733 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003734 result = SearchRegExpMultiple(isolate,
3735 subject,
3736 regexp,
3737 last_match_info,
3738 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 }
3740 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003742 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3743 return Failure::Exception();
3744}
3745
3746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003747RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 NoHandleAllocation ha;
3749 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003750 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003751 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003753 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003754 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003756 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003757 // Character array used for conversion.
3758 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return isolate->heap()->
3760 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003761 }
3762 }
3763
3764 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003765 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 }
3769 if (isinf(value)) {
3770 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003776 MaybeObject* result =
3777 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778 DeleteArray(str);
3779 return result;
3780}
3781
3782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003783RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 NoHandleAllocation ha;
3785 ASSERT(args.length() == 2);
3786
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003787 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003789 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 }
3791 if (isinf(value)) {
3792 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003794 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003796 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003797 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 int f = FastD2I(f_number);
3799 RUNTIME_ASSERT(f >= 0);
3800 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 MaybeObject* res =
3802 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805}
3806
3807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003808RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 NoHandleAllocation ha;
3810 ASSERT(args.length() == 2);
3811
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003813 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 }
3816 if (isinf(value)) {
3817 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003818 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003822 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 int f = FastD2I(f_number);
3824 RUNTIME_ASSERT(f >= -1 && f <= 20);
3825 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003826 MaybeObject* res =
3827 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830}
3831
3832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003833RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 NoHandleAllocation ha;
3835 ASSERT(args.length() == 2);
3836
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003837 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003839 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 }
3841 if (isinf(value)) {
3842 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003843 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003844 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003846 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003847 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848 int f = FastD2I(f_number);
3849 RUNTIME_ASSERT(f >= 1 && f <= 21);
3850 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003851 MaybeObject* res =
3852 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003855}
3856
3857
3858// Returns a single character string where first character equals
3859// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003860static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003861 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003862 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003863 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003864 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003866 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867}
3868
3869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003870MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3871 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003872 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003873 // Handle [] indexing on Strings
3874 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003875 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3876 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 }
3878
3879 // Handle [] indexing on String objects
3880 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003881 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3882 Handle<Object> result =
3883 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3884 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 }
3886
3887 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003888 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 return prototype->GetElement(index);
3890 }
3891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003892 return GetElement(object, index);
3893}
3894
3895
lrn@chromium.org303ada72010-10-27 09:33:13 +00003896MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003897 return object->GetElement(index);
3898}
3899
3900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3902 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003903 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003907 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 isolate->factory()->NewTypeError("non_object_property_load",
3910 HandleVector(args, 2));
3911 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912 }
3913
3914 // Check if the given key is an array index.
3915 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003916 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918 }
3919
3920 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003921 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003923 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003925 bool has_pending_exception = false;
3926 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003927 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003929 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003930 }
3931
ager@chromium.org32912102009-01-16 10:38:43 +00003932 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 // the element if so.
3934 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003936 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003937 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939}
3940
3941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003942RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 NoHandleAllocation ha;
3944 ASSERT(args.length() == 2);
3945
3946 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003947 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003949 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950}
3951
3952
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003953// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003954RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003955 NoHandleAllocation ha;
3956 ASSERT(args.length() == 2);
3957
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003958 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003959 // itself.
3960 //
3961 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003962 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003963 // global proxy object never has properties. This is the case
3964 // because the global proxy object forwards everything to its hidden
3965 // prototype including local lookups.
3966 //
3967 // Additionally, we need to make sure that we do not cache results
3968 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003969 if (args[0]->IsJSObject() &&
3970 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003971 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003972 args[1]->IsString()) {
3973 JSObject* receiver = JSObject::cast(args[0]);
3974 String* key = String::cast(args[1]);
3975 if (receiver->HasFastProperties()) {
3976 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003977 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3979 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003980 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003981 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003984 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003985 LookupResult result;
3986 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003987 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003988 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003990 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003991 }
3992 } else {
3993 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003994 StringDictionary* dictionary = receiver->property_dictionary();
3995 int entry = dictionary->FindEntry(key);
3996 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003997 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003998 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003999 if (!receiver->IsGlobalObject()) return value;
4000 value = JSGlobalPropertyCell::cast(value)->value();
4001 if (!value->IsTheHole()) return value;
4002 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004003 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004004 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004005 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4006 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004008 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004009 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004010 if (index >= 0 && index < str->length()) {
4011 Handle<Object> result = GetCharAt(str, index);
4012 return *result;
4013 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004014 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004015
4016 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return Runtime::GetObjectProperty(isolate,
4018 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004019 args.at<Object>(1));
4020}
4021
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004022// Implements part of 8.12.9 DefineOwnProperty.
4023// There are 3 cases that lead here:
4024// Step 4b - define a new accessor property.
4025// Steps 9c & 12 - replace an existing data property with an accessor property.
4026// Step 12 - update an existing accessor property with an accessor or generic
4027// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004028RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004029 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004031 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4032 CONVERT_CHECKED(String, name, args[1]);
4033 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004034 Object* fun = args[3];
4035 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004036 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4037 int unchecked = flag_attr->value();
4038 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4039 RUNTIME_ASSERT(!obj->IsNull());
4040 LookupResult result;
4041 obj->LocalLookupRealNamedProperty(name, &result);
4042
4043 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4044 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4045 // delete it to avoid running into trouble in DefineAccessor, which
4046 // handles this incorrectly if the property is readonly (does nothing)
4047 if (result.IsProperty() &&
4048 (result.type() == FIELD || result.type() == NORMAL
4049 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004050 Object* ok;
4051 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004052 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4054 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004055 }
4056 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4057}
4058
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004059// Implements part of 8.12.9 DefineOwnProperty.
4060// There are 3 cases that lead here:
4061// Step 4a - define a new data property.
4062// Steps 9b & 12 - replace an existing accessor property with a data property.
4063// Step 12 - update an existing data property with a data or generic
4064// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004065RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004067 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004068 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4069 CONVERT_ARG_CHECKED(String, name, 1);
4070 Handle<Object> obj_value = args.at<Object>(2);
4071
4072 CONVERT_CHECKED(Smi, flag, args[3]);
4073 int unchecked = flag->value();
4074 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4075
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004076 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4077
4078 // Check if this is an element.
4079 uint32_t index;
4080 bool is_element = name->AsArrayIndex(&index);
4081
4082 // Special case for elements if any of the flags are true.
4083 // If elements are in fast case we always implicitly assume that:
4084 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4085 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4086 is_element) {
4087 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004088 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004089 // We do not need to do access checks here since these has already
4090 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004091 Handle<Object> proto(js_object->GetPrototype());
4092 // If proxy is detached, ignore the assignment. Alternatively,
4093 // we could throw an exception.
4094 if (proto->IsNull()) return *obj_value;
4095 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004096 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004097 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004098 // Make sure that we never go back to fast case.
4099 dictionary->set_requires_slow_elements();
4100 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004101 Handle<NumberDictionary> extended_dictionary =
4102 NumberDictionarySet(dictionary, index, obj_value, details);
4103 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004104 if (js_object->GetElementsKind() ==
4105 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4106 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4107 } else {
4108 js_object->set_elements(*extended_dictionary);
4109 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004110 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004111 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004112 }
4113
ager@chromium.org5c838252010-02-19 08:53:10 +00004114 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004115 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004116
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004117 // To be compatible with safari we do not change the value on API objects
4118 // in defineProperty. Firefox disagrees here, and actually changes the value.
4119 if (result.IsProperty() &&
4120 (result.type() == CALLBACKS) &&
4121 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004123 }
4124
ager@chromium.org5c838252010-02-19 08:53:10 +00004125 // Take special care when attributes are different and there is already
4126 // a property. For simplicity we normalize the property which enables us
4127 // to not worry about changing the instance_descriptor and creating a new
4128 // map. The current version of SetObjectProperty does not handle attributes
4129 // correctly in the case where a property is a field and is reset with
4130 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004131 if (result.IsProperty() &&
4132 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004133 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004134 if (js_object->IsJSGlobalProxy()) {
4135 // Since the result is a property, the prototype will exist so
4136 // we don't have to check for null.
4137 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004138 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004139 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004140 // Use IgnoreAttributes version since a readonly property may be
4141 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004142 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4143 *obj_value,
4144 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004145 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147 return Runtime::ForceSetObjectProperty(isolate,
4148 js_object,
4149 name,
4150 obj_value,
4151 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004152}
4153
4154
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004155// Special case for elements if any of the flags are true.
4156// If elements are in fast case we always implicitly assume that:
4157// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4158static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4159 Handle<JSObject> js_object,
4160 uint32_t index,
4161 Handle<Object> value,
4162 PropertyAttributes attr) {
4163 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004164 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004165 // Make sure that we never go back to fast case.
4166 dictionary->set_requires_slow_elements();
4167 PropertyDetails details = PropertyDetails(attr, NORMAL);
4168 Handle<NumberDictionary> extended_dictionary =
4169 NumberDictionarySet(dictionary, index, value, details);
4170 if (*extended_dictionary != *dictionary) {
4171 js_object->set_elements(*extended_dictionary);
4172 }
4173 return *value;
4174}
4175
4176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4178 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004179 Handle<Object> key,
4180 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004181 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004182 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 isolate->factory()->NewTypeError("non_object_property_store",
4189 HandleVector(args, 2));
4190 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // If the object isn't a JavaScript object, we ignore the store.
4194 if (!object->IsJSObject()) return *value;
4195
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 // Check if the given key is an array index.
4199 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004200 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4202 // of a string using [] notation. We need to support this too in
4203 // JavaScript.
4204 // In the case of a String object we just need to redirect the assignment to
4205 // the underlying string if the index is in range. Since the underlying
4206 // string does nothing with the assignment then we can ignore such
4207 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004208 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004212 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4213 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4214 }
4215
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004216 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004217 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 return *value;
4219 }
4220
4221 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004222 Handle<Object> result;
4223 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004224 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4225 return NormalizeObjectSetElement(isolate,
4226 js_object,
4227 index,
4228 value,
4229 attr);
4230 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004231 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004233 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004234 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004235 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004237 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 return *value;
4239 }
4240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 bool has_pending_exception = false;
4243 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4244 if (has_pending_exception) return Failure::Exception();
4245 Handle<String> name = Handle<String>::cast(converted);
4246
4247 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004248 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004250 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251 }
4252}
4253
4254
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4256 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004257 Handle<Object> key,
4258 Handle<Object> value,
4259 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004261
4262 // Check if the given key is an array index.
4263 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004264 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004265 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4266 // of a string using [] notation. We need to support this too in
4267 // JavaScript.
4268 // In the case of a String object we just need to redirect the assignment to
4269 // the underlying string if the index is in range. Since the underlying
4270 // string does nothing with the assignment then we can ignore such
4271 // assignments.
4272 if (js_object->IsStringObjectWithCharacterAt(index)) {
4273 return *value;
4274 }
4275
whesse@chromium.org7b260152011-06-20 15:33:18 +00004276 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004277 }
4278
4279 if (key->IsString()) {
4280 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004281 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004282 } else {
4283 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004284 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004285 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4286 *value,
4287 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004288 }
4289 }
4290
4291 // Call-back into JavaScript to convert the key to a string.
4292 bool has_pending_exception = false;
4293 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4294 if (has_pending_exception) return Failure::Exception();
4295 Handle<String> name = Handle<String>::cast(converted);
4296
4297 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004298 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004299 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004300 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004301 }
4302}
4303
4304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004306 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004307 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004308 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004309
4310 // Check if the given key is an array index.
4311 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004312 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004313 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4314 // characters of a string using [] notation. In the case of a
4315 // String object we just need to redirect the deletion to the
4316 // underlying string if the index is in range. Since the
4317 // underlying string does nothing with the deletion, we can ignore
4318 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004319 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004321 }
4322
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004323 return JSObject::cast(*receiver)->DeleteElement(
4324 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004325 }
4326
4327 Handle<String> key_string;
4328 if (key->IsString()) {
4329 key_string = Handle<String>::cast(key);
4330 } else {
4331 // Call-back into JavaScript to convert the key to a string.
4332 bool has_pending_exception = false;
4333 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4334 if (has_pending_exception) return Failure::Exception();
4335 key_string = Handle<String>::cast(converted);
4336 }
4337
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004338 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004339 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004340}
4341
4342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004343RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004345 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346
4347 Handle<Object> object = args.at<Object>(0);
4348 Handle<Object> key = args.at<Object>(1);
4349 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004350 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004351 RUNTIME_ASSERT(
4352 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004354 PropertyAttributes attributes =
4355 static_cast<PropertyAttributes>(unchecked_attributes);
4356
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004357 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004358 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004359 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004360 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4361 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004362 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004363 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004365 return Runtime::SetObjectProperty(isolate,
4366 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004367 key,
4368 value,
4369 attributes,
4370 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004371}
4372
4373
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004374// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004375// This is used to decide if we should transform null and undefined
4376// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004377RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004378 NoHandleAllocation ha;
4379 RUNTIME_ASSERT(args.length() == 1);
4380
4381 Handle<Object> object = args.at<Object>(0);
4382
4383 if (object->IsJSFunction()) {
4384 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004385 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004386 }
4387 return isolate->heap()->undefined_value();
4388}
4389
4390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391// Set a local property, even if it is READ_ONLY. If the property does not
4392// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004393RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004395 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 CONVERT_CHECKED(JSObject, object, args[0]);
4397 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004398 // Compute attributes.
4399 PropertyAttributes attributes = NONE;
4400 if (args.length() == 4) {
4401 CONVERT_CHECKED(Smi, value_obj, args[3]);
4402 int unchecked_value = value_obj->value();
4403 // Only attribute bits should be set.
4404 RUNTIME_ASSERT(
4405 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4406 attributes = static_cast<PropertyAttributes>(unchecked_value);
4407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004409 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004410 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411}
4412
4413
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004414RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004416 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004418 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004419 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004420 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004421 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004422 ? JSReceiver::STRICT_DELETION
4423 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424}
4425
4426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427static Object* HasLocalPropertyImplementation(Isolate* isolate,
4428 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004429 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004431 // Handle hidden prototypes. If there's a hidden prototype above this thing
4432 // then we have to check it for properties, because they are supposed to
4433 // look like they are on this object.
4434 Handle<Object> proto(object->GetPrototype());
4435 if (proto->IsJSObject() &&
4436 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 return HasLocalPropertyImplementation(isolate,
4438 Handle<JSObject>::cast(proto),
4439 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004440 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004441 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004442}
4443
4444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004445RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 NoHandleAllocation ha;
4447 ASSERT(args.length() == 2);
4448 CONVERT_CHECKED(String, key, args[1]);
4449
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004450 uint32_t index;
4451 const bool key_is_array_index = key->AsArrayIndex(&index);
4452
ager@chromium.org9085a012009-05-11 19:22:57 +00004453 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004455 if (obj->IsJSObject()) {
4456 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004457 // Fast case: either the key is a real named property or it is not
4458 // an array index and there are no interceptors or hidden
4459 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004460 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004461 Map* map = object->map();
4462 if (!key_is_array_index &&
4463 !map->has_named_interceptor() &&
4464 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4465 return isolate->heap()->false_value();
4466 }
4467 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 HandleScope scope(isolate);
4469 return HasLocalPropertyImplementation(isolate,
4470 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004471 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004472 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004474 String* string = String::cast(obj);
4475 if (index < static_cast<uint32_t>(string->length())) {
4476 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 }
4478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480}
4481
4482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 NoHandleAllocation na;
4485 ASSERT(args.length() == 2);
4486
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004487 // Only JS receivers can have properties.
4488 if (args[0]->IsJSReceiver()) {
4489 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004491 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494}
4495
4496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004497RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 NoHandleAllocation na;
4499 ASSERT(args.length() == 2);
4500
4501 // Only JS objects can have elements.
4502 if (args[0]->IsJSObject()) {
4503 JSObject* object = JSObject::cast(args[0]);
4504 CONVERT_CHECKED(Smi, index_obj, args[1]);
4505 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509}
4510
4511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004512RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 NoHandleAllocation ha;
4514 ASSERT(args.length() == 2);
4515
4516 CONVERT_CHECKED(JSObject, object, args[0]);
4517 CONVERT_CHECKED(String, key, args[1]);
4518
4519 uint32_t index;
4520 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522 }
4523
ager@chromium.org870a0b62008-11-04 11:43:05 +00004524 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004525 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526}
4527
4528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004530 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004532 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 return *GetKeysFor(object);
4534}
4535
4536
4537// Returns either a FixedArray as Runtime_GetPropertyNames,
4538// or, if the given object has an enum cache that contains
4539// all enumerable properties of the object and its prototypes
4540// have none, the map of the object. This is used to speed up
4541// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004542RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 ASSERT(args.length() == 1);
4544
4545 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4546
4547 if (raw_object->IsSimpleEnum()) return raw_object->map();
4548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004551 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4552 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553
4554 // Test again, since cache may have been built by preceding call.
4555 if (object->IsSimpleEnum()) return object->map();
4556
4557 return *content;
4558}
4559
4560
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004561// Find the length of the prototype chain that is to to handled as one. If a
4562// prototype object is hidden it is to be viewed as part of the the object it
4563// is prototype for.
4564static int LocalPrototypeChainLength(JSObject* obj) {
4565 int count = 1;
4566 Object* proto = obj->GetPrototype();
4567 while (proto->IsJSObject() &&
4568 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4569 count++;
4570 proto = JSObject::cast(proto)->GetPrototype();
4571 }
4572 return count;
4573}
4574
4575
4576// Return the names of the local named properties.
4577// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004578RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004579 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004580 ASSERT(args.length() == 1);
4581 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 }
4584 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4585
4586 // Skip the global proxy as it has no properties and always delegates to the
4587 // real global object.
4588 if (obj->IsJSGlobalProxy()) {
4589 // Only collect names if access is permitted.
4590 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 !isolate->MayNamedAccess(*obj,
4592 isolate->heap()->undefined_value(),
4593 v8::ACCESS_KEYS)) {
4594 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4595 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004596 }
4597 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4598 }
4599
4600 // Find the number of objects making up this.
4601 int length = LocalPrototypeChainLength(*obj);
4602
4603 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004604 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004605 int total_property_count = 0;
4606 Handle<JSObject> jsproto = obj;
4607 for (int i = 0; i < length; i++) {
4608 // Only collect names if access is permitted.
4609 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004610 !isolate->MayNamedAccess(*jsproto,
4611 isolate->heap()->undefined_value(),
4612 v8::ACCESS_KEYS)) {
4613 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4614 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004615 }
4616 int n;
4617 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4618 local_property_count[i] = n;
4619 total_property_count += n;
4620 if (i < length - 1) {
4621 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4622 }
4623 }
4624
4625 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 Handle<FixedArray> names =
4627 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004628
4629 // Get the property names.
4630 jsproto = obj;
4631 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004632 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004633 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004634 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4635 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004636 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004637 proto_with_hidden_properties++;
4638 }
4639 if (i < length - 1) {
4640 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4641 }
4642 }
4643
4644 // Filter out name of hidden propeties object.
4645 if (proto_with_hidden_properties > 0) {
4646 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004647 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004648 names->length() - proto_with_hidden_properties);
4649 int dest_pos = 0;
4650 for (int i = 0; i < total_property_count; i++) {
4651 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004652 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004653 continue;
4654 }
4655 names->set(dest_pos++, name);
4656 }
4657 }
4658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004659 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004660}
4661
4662
4663// Return the names of the local indexed properties.
4664// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004665RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004666 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004667 ASSERT(args.length() == 1);
4668 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004670 }
4671 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4672
4673 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004675 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004677}
4678
4679
4680// Return information on whether an object has a named or indexed interceptor.
4681// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004684 ASSERT(args.length() == 1);
4685 if (!args[0]->IsJSObject()) {
4686 return Smi::FromInt(0);
4687 }
4688 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4689
4690 int result = 0;
4691 if (obj->HasNamedInterceptor()) result |= 2;
4692 if (obj->HasIndexedInterceptor()) result |= 1;
4693
4694 return Smi::FromInt(result);
4695}
4696
4697
4698// Return property names from named interceptor.
4699// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004702 ASSERT(args.length() == 1);
4703 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4704
4705 if (obj->HasNamedInterceptor()) {
4706 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4707 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4708 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004710}
4711
4712
4713// Return element names from indexed interceptor.
4714// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004717 ASSERT(args.length() == 1);
4718 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4719
4720 if (obj->HasIndexedInterceptor()) {
4721 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4722 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4723 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004724 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004725}
4726
4727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004728RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004729 ASSERT_EQ(args.length(), 1);
4730 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004731 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004732 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004733
4734 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004735 // Do access checks before going to the global object.
4736 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004738 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004739 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4740 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004741 }
4742
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004743 Handle<Object> proto(object->GetPrototype());
4744 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004746 object = Handle<JSObject>::cast(proto);
4747 }
4748
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004749 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4750 LOCAL_ONLY);
4751 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4752 // property array and since the result is mutable we have to create
4753 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004754 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004756 for (int i = 0; i < length; i++) {
4757 Object* entry = contents->get(i);
4758 if (entry->IsString()) {
4759 copy->set(i, entry);
4760 } else {
4761 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 HandleScope scope(isolate);
4763 Handle<Object> entry_handle(entry, isolate);
4764 Handle<Object> entry_str =
4765 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004766 copy->set(i, *entry_str);
4767 }
4768 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004770}
4771
4772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004773RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 NoHandleAllocation ha;
4775 ASSERT(args.length() == 1);
4776
4777 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004778 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 it.AdvanceToArgumentsFrame();
4780 JavaScriptFrame* frame = it.frame();
4781
4782 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004783 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784
4785 // Try to convert the key to an index. If successful and within
4786 // index return the the argument from the frame.
4787 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004788 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789 return frame->GetParameter(index);
4790 }
4791
4792 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 bool exception = false;
4795 Handle<Object> converted =
4796 Execution::ToString(args.at<Object>(0), &exception);
4797 if (exception) return Failure::Exception();
4798 Handle<String> key = Handle<String>::cast(converted);
4799
4800 // Try to convert the string key into an array index.
4801 if (key->AsArrayIndex(&index)) {
4802 if (index < n) {
4803 return frame->GetParameter(index);
4804 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 }
4807 }
4808
4809 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004810 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4811 if (key->Equals(isolate->heap()->callee_symbol())) {
4812 Object* function = frame->function();
4813 if (function->IsJSFunction() &&
4814 JSFunction::cast(function)->shared()->strict_mode()) {
4815 return isolate->Throw(*isolate->factory()->NewTypeError(
4816 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4817 }
4818 return function;
4819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820
4821 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004822 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823}
4824
4825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004826RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004827 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004828
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004829 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004830 Handle<Object> object = args.at<Object>(0);
4831 if (object->IsJSObject()) {
4832 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004833 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004834 MaybeObject* ok = js_object->TransformToFastProperties(0);
4835 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004836 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004837 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004838 return *object;
4839}
4840
4841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004842RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004843 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004844
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004845 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004846 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004847 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004848 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004849 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004850 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004851 return *object;
4852}
4853
4854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004855RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 NoHandleAllocation ha;
4857 ASSERT(args.length() == 1);
4858
4859 return args[0]->ToBoolean();
4860}
4861
4862
4863// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4864// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004865RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 NoHandleAllocation ha;
4867
4868 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 HeapObject* heap_obj = HeapObject::cast(obj);
4871
4872 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 if (heap_obj->map()->is_undetectable()) {
4874 return isolate->heap()->undefined_symbol();
4875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876
4877 InstanceType instance_type = heap_obj->map()->instance_type();
4878 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004879 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004880 }
4881
4882 switch (instance_type) {
4883 case ODDBALL_TYPE:
4884 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 }
4887 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004888 return FLAG_harmony_typeof
4889 ? isolate->heap()->null_symbol()
4890 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 }
4892 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004893 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004894 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 default:
4897 // For any kind of object not handled above, the spec rule for
4898 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 }
4901}
4902
4903
lrn@chromium.org25156de2010-04-06 13:10:27 +00004904static bool AreDigits(const char*s, int from, int to) {
4905 for (int i = from; i < to; i++) {
4906 if (s[i] < '0' || s[i] > '9') return false;
4907 }
4908
4909 return true;
4910}
4911
4912
4913static int ParseDecimalInteger(const char*s, int from, int to) {
4914 ASSERT(to - from < 10); // Overflow is not possible.
4915 ASSERT(from < to);
4916 int d = s[from] - '0';
4917
4918 for (int i = from + 1; i < to; i++) {
4919 d = 10 * d + (s[i] - '0');
4920 }
4921
4922 return d;
4923}
4924
4925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004926RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 NoHandleAllocation ha;
4928 ASSERT(args.length() == 1);
4929 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004930 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004931
4932 // Fast case: short integer or some sorts of junk values.
4933 int len = subject->length();
4934 if (subject->IsSeqAsciiString()) {
4935 if (len == 0) return Smi::FromInt(0);
4936
4937 char const* data = SeqAsciiString::cast(subject)->GetChars();
4938 bool minus = (data[0] == '-');
4939 int start_pos = (minus ? 1 : 0);
4940
4941 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004942 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004943 } else if (data[start_pos] > '9') {
4944 // Fast check for a junk value. A valid string may start from a
4945 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4946 // the 'I' character ('Infinity'). All of that have codes not greater than
4947 // '9' except 'I'.
4948 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004950 }
4951 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4952 // The maximal/minimal smi has 10 digits. If the string has less digits we
4953 // know it will fit into the smi-data type.
4954 int d = ParseDecimalInteger(data, start_pos, len);
4955 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004956 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004957 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004958 } else if (!subject->HasHashCode() &&
4959 len <= String::kMaxArrayIndexSize &&
4960 (len == 1 || data[0] != '0')) {
4961 // String hash is not calculated yet but all the data are present.
4962 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004963 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004964#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004965 subject->Hash(); // Force hash calculation.
4966 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4967 static_cast<int>(hash));
4968#endif
4969 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004970 }
4971 return Smi::FromInt(d);
4972 }
4973 }
4974
4975 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004976 return isolate->heap()->NumberFromDouble(
4977 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978}
4979
4980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004981RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 NoHandleAllocation ha;
4983 ASSERT(args.length() == 1);
4984
4985 CONVERT_CHECKED(JSArray, codes, args[0]);
4986 int length = Smi::cast(codes->length())->value();
4987
4988 // Check if the string can be ASCII.
4989 int i;
4990 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004991 Object* element;
4992 { MaybeObject* maybe_element = codes->GetElement(i);
4993 // We probably can't get an exception here, but just in order to enforce
4994 // the checking of inputs in the runtime calls we check here.
4995 if (!maybe_element->ToObject(&element)) return maybe_element;
4996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4998 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4999 break;
5000 }
5001
lrn@chromium.org303ada72010-10-27 09:33:13 +00005002 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005007 }
5008
lrn@chromium.org303ada72010-10-27 09:33:13 +00005009 Object* object = NULL;
5010 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 String* result = String::cast(object);
5012 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005013 Object* element;
5014 { MaybeObject* maybe_element = codes->GetElement(i);
5015 if (!maybe_element->ToObject(&element)) return maybe_element;
5016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005018 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005019 }
5020 return result;
5021}
5022
5023
5024// kNotEscaped is generated by the following:
5025//
5026// #!/bin/perl
5027// for (my $i = 0; $i < 256; $i++) {
5028// print "\n" if $i % 16 == 0;
5029// my $c = chr($i);
5030// my $escaped = 1;
5031// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5032// print $escaped ? "0, " : "1, ";
5033// }
5034
5035
5036static bool IsNotEscaped(uint16_t character) {
5037 // Only for 8 bit characters, the rest are always escaped (in a different way)
5038 ASSERT(character < 256);
5039 static const char kNotEscaped[256] = {
5040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5043 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5044 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5045 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5046 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5047 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5048 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5049 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5050 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5051 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5052 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5053 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5054 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5055 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5056 };
5057 return kNotEscaped[character] != 0;
5058}
5059
5060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005061RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 const char hex_chars[] = "0123456789ABCDEF";
5063 NoHandleAllocation ha;
5064 ASSERT(args.length() == 1);
5065 CONVERT_CHECKED(String, source, args[0]);
5066
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005067 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068
5069 int escaped_length = 0;
5070 int length = source->length();
5071 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 Access<StringInputBuffer> buffer(
5073 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005074 buffer->Reset(source);
5075 while (buffer->has_more()) {
5076 uint16_t character = buffer->GetNext();
5077 if (character >= 256) {
5078 escaped_length += 6;
5079 } else if (IsNotEscaped(character)) {
5080 escaped_length++;
5081 } else {
5082 escaped_length += 3;
5083 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005084 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005085 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005086 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088 return Failure::OutOfMemoryException();
5089 }
5090 }
5091 }
5092 // No length change implies no change. Return original string if no change.
5093 if (escaped_length == length) {
5094 return source;
5095 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005096 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 { MaybeObject* maybe_o =
5098 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005099 if (!maybe_o->ToObject(&o)) return maybe_o;
5100 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005101 String* destination = String::cast(o);
5102 int dest_position = 0;
5103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 Access<StringInputBuffer> buffer(
5105 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005106 buffer->Rewind();
5107 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005108 uint16_t chr = buffer->GetNext();
5109 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005110 destination->Set(dest_position, '%');
5111 destination->Set(dest_position+1, 'u');
5112 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5113 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5114 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5115 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005117 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005118 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 dest_position++;
5120 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005121 destination->Set(dest_position, '%');
5122 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5123 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 dest_position += 3;
5125 }
5126 }
5127 return destination;
5128}
5129
5130
5131static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5132 static const signed char kHexValue['g'] = {
5133 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5134 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5135 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5136 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5137 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5138 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5139 -1, 10, 11, 12, 13, 14, 15 };
5140
5141 if (character1 > 'f') return -1;
5142 int hi = kHexValue[character1];
5143 if (hi == -1) return -1;
5144 if (character2 > 'f') return -1;
5145 int lo = kHexValue[character2];
5146 if (lo == -1) return -1;
5147 return (hi << 4) + lo;
5148}
5149
5150
ager@chromium.org870a0b62008-11-04 11:43:05 +00005151static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005152 int i,
5153 int length,
5154 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005155 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005156 int32_t hi = 0;
5157 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005158 if (character == '%' &&
5159 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005160 source->Get(i + 1) == 'u' &&
5161 (hi = TwoDigitHex(source->Get(i + 2),
5162 source->Get(i + 3))) != -1 &&
5163 (lo = TwoDigitHex(source->Get(i + 4),
5164 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005165 *step = 6;
5166 return (hi << 8) + lo;
5167 } else if (character == '%' &&
5168 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005169 (lo = TwoDigitHex(source->Get(i + 1),
5170 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171 *step = 3;
5172 return lo;
5173 } else {
5174 *step = 1;
5175 return character;
5176 }
5177}
5178
5179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005180RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 NoHandleAllocation ha;
5182 ASSERT(args.length() == 1);
5183 CONVERT_CHECKED(String, source, args[0]);
5184
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005185 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186
5187 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005188 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189
5190 int unescaped_length = 0;
5191 for (int i = 0; i < length; unescaped_length++) {
5192 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005193 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 i += step;
5197 }
5198
5199 // No length change implies no change. Return original string if no change.
5200 if (unescaped_length == length)
5201 return source;
5202
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 { MaybeObject* maybe_o =
5205 ascii ?
5206 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5207 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005208 if (!maybe_o->ToObject(&o)) return maybe_o;
5209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 String* destination = String::cast(o);
5211
5212 int dest_position = 0;
5213 for (int i = 0; i < length; dest_position++) {
5214 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005215 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 i += step;
5217 }
5218 return destination;
5219}
5220
5221
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005222static const unsigned int kQuoteTableLength = 128u;
5223
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224static const int kJsonQuotesCharactersPerEntry = 8;
5225static const char* const JsonQuotes =
5226 "\\u0000 \\u0001 \\u0002 \\u0003 "
5227 "\\u0004 \\u0005 \\u0006 \\u0007 "
5228 "\\b \\t \\n \\u000b "
5229 "\\f \\r \\u000e \\u000f "
5230 "\\u0010 \\u0011 \\u0012 \\u0013 "
5231 "\\u0014 \\u0015 \\u0016 \\u0017 "
5232 "\\u0018 \\u0019 \\u001a \\u001b "
5233 "\\u001c \\u001d \\u001e \\u001f "
5234 " ! \\\" # "
5235 "$ % & ' "
5236 "( ) * + "
5237 ", - . / "
5238 "0 1 2 3 "
5239 "4 5 6 7 "
5240 "8 9 : ; "
5241 "< = > ? "
5242 "@ A B C "
5243 "D E F G "
5244 "H I J K "
5245 "L M N O "
5246 "P Q R S "
5247 "T U V W "
5248 "X Y Z [ "
5249 "\\\\ ] ^ _ "
5250 "` a b c "
5251 "d e f g "
5252 "h i j k "
5253 "l m n o "
5254 "p q r s "
5255 "t u v w "
5256 "x y z { "
5257 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005258
5259
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005260// For a string that is less than 32k characters it should always be
5261// possible to allocate it in new space.
5262static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5263
5264
5265// Doing JSON quoting cannot make the string more than this many times larger.
5266static const int kJsonQuoteWorstCaseBlowup = 6;
5267
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005268static const int kSpaceForQuotesAndComma = 3;
5269static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005270
5271// Covers the entire ASCII range (all other characters are unchanged by JSON
5272// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005273static const byte JsonQuoteLengths[kQuoteTableLength] = {
5274 6, 6, 6, 6, 6, 6, 6, 6,
5275 2, 2, 2, 6, 2, 2, 6, 6,
5276 6, 6, 6, 6, 6, 6, 6, 6,
5277 6, 6, 6, 6, 6, 6, 6, 6,
5278 1, 1, 2, 1, 1, 1, 1, 1,
5279 1, 1, 1, 1, 1, 1, 1, 1,
5280 1, 1, 1, 1, 1, 1, 1, 1,
5281 1, 1, 1, 1, 1, 1, 1, 1,
5282 1, 1, 1, 1, 1, 1, 1, 1,
5283 1, 1, 1, 1, 1, 1, 1, 1,
5284 1, 1, 1, 1, 1, 1, 1, 1,
5285 1, 1, 1, 1, 2, 1, 1, 1,
5286 1, 1, 1, 1, 1, 1, 1, 1,
5287 1, 1, 1, 1, 1, 1, 1, 1,
5288 1, 1, 1, 1, 1, 1, 1, 1,
5289 1, 1, 1, 1, 1, 1, 1, 1,
5290};
5291
5292
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005293template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005295
5296
5297template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005298MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5299 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005300}
5301
5302
5303template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005304MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5305 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005306}
5307
5308
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005309template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5311 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005312 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005313 const Char* read_cursor = characters.start();
5314 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005315 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005316 int quoted_length = kSpaceForQuotes;
5317 while (read_cursor < end) {
5318 Char c = *(read_cursor++);
5319 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5320 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005321 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005322 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005323 }
5324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005325 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5326 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005327 Object* new_object;
5328 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005329 return new_alloc;
5330 }
5331 StringType* new_string = StringType::cast(new_object);
5332
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005333 Char* write_cursor = reinterpret_cast<Char*>(
5334 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005335 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005336 *(write_cursor++) = '"';
5337
5338 read_cursor = characters.start();
5339 while (read_cursor < end) {
5340 Char c = *(read_cursor++);
5341 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5342 *(write_cursor++) = c;
5343 } else {
5344 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5345 const char* replacement = JsonQuotes +
5346 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5347 for (int i = 0; i < len; i++) {
5348 *write_cursor++ = *replacement++;
5349 }
5350 }
5351 }
5352 *(write_cursor++) = '"';
5353 return new_string;
5354}
5355
5356
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005357template <typename SinkChar, typename SourceChar>
5358static inline SinkChar* WriteQuoteJsonString(
5359 Isolate* isolate,
5360 SinkChar* write_cursor,
5361 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005362 // SinkChar is only char if SourceChar is guaranteed to be char.
5363 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005364 const SourceChar* read_cursor = characters.start();
5365 const SourceChar* end = read_cursor + characters.length();
5366 *(write_cursor++) = '"';
5367 while (read_cursor < end) {
5368 SourceChar c = *(read_cursor++);
5369 if (sizeof(SourceChar) > 1u &&
5370 static_cast<unsigned>(c) >= kQuoteTableLength) {
5371 *(write_cursor++) = static_cast<SinkChar>(c);
5372 } else {
5373 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5374 const char* replacement = JsonQuotes +
5375 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5376 write_cursor[0] = replacement[0];
5377 if (len > 1) {
5378 write_cursor[1] = replacement[1];
5379 if (len > 2) {
5380 ASSERT(len == 6);
5381 write_cursor[2] = replacement[2];
5382 write_cursor[3] = replacement[3];
5383 write_cursor[4] = replacement[4];
5384 write_cursor[5] = replacement[5];
5385 }
5386 }
5387 write_cursor += len;
5388 }
5389 }
5390 *(write_cursor++) = '"';
5391 return write_cursor;
5392}
5393
5394
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005395template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396static MaybeObject* QuoteJsonString(Isolate* isolate,
5397 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005398 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005399 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005400 int worst_case_length =
5401 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005402 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005403 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005404 }
5405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5407 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005408 Object* new_object;
5409 if (!new_alloc->ToObject(&new_object)) {
5410 return new_alloc;
5411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005413 // Even if our string is small enough to fit in new space we still have to
5414 // handle it being allocated in old space as may happen in the third
5415 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5416 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005417 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005418 }
5419 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005421
5422 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5423 Char* write_cursor = reinterpret_cast<Char*>(
5424 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005425 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005426 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5427 write_cursor,
5428 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005429 int final_length = static_cast<int>(
5430 write_cursor - reinterpret_cast<Char*>(
5431 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005432 isolate->heap()->new_space()->
5433 template ShrinkStringAtAllocationBoundary<StringType>(
5434 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005435 return new_string;
5436}
5437
5438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005439RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005440 NoHandleAllocation ha;
5441 CONVERT_CHECKED(String, str, args[0]);
5442 if (!str->IsFlat()) {
5443 MaybeObject* try_flatten = str->TryFlatten();
5444 Object* flat;
5445 if (!try_flatten->ToObject(&flat)) {
5446 return try_flatten;
5447 }
5448 str = String::cast(flat);
5449 ASSERT(str->IsFlat());
5450 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005451 String::FlatContent flat = str->GetFlatContent();
5452 ASSERT(flat.IsFlat());
5453 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005455 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005456 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005457 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005458 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005459 }
5460}
5461
5462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005463RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005464 NoHandleAllocation ha;
5465 CONVERT_CHECKED(String, str, args[0]);
5466 if (!str->IsFlat()) {
5467 MaybeObject* try_flatten = str->TryFlatten();
5468 Object* flat;
5469 if (!try_flatten->ToObject(&flat)) {
5470 return try_flatten;
5471 }
5472 str = String::cast(flat);
5473 ASSERT(str->IsFlat());
5474 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005475 String::FlatContent flat = str->GetFlatContent();
5476 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005478 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005479 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005480 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005481 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005482 }
5483}
5484
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005485
5486template <typename Char, typename StringType>
5487static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5488 FixedArray* array,
5489 int worst_case_length) {
5490 int length = array->length();
5491
5492 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5493 worst_case_length);
5494 Object* new_object;
5495 if (!new_alloc->ToObject(&new_object)) {
5496 return new_alloc;
5497 }
5498 if (!isolate->heap()->new_space()->Contains(new_object)) {
5499 // Even if our string is small enough to fit in new space we still have to
5500 // handle it being allocated in old space as may happen in the third
5501 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5502 // CEntryStub::GenerateCore.
5503 return isolate->heap()->undefined_value();
5504 }
5505 AssertNoAllocation no_gc;
5506 StringType* new_string = StringType::cast(new_object);
5507 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5508
5509 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5510 Char* write_cursor = reinterpret_cast<Char*>(
5511 new_string->address() + SeqAsciiString::kHeaderSize);
5512 *(write_cursor++) = '[';
5513 for (int i = 0; i < length; i++) {
5514 if (i != 0) *(write_cursor++) = ',';
5515 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005516 String::FlatContent content = str->GetFlatContent();
5517 ASSERT(content.IsFlat());
5518 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005519 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5520 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005521 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005522 } else {
5523 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5524 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005525 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005526 }
5527 }
5528 *(write_cursor++) = ']';
5529
5530 int final_length = static_cast<int>(
5531 write_cursor - reinterpret_cast<Char*>(
5532 new_string->address() + SeqAsciiString::kHeaderSize));
5533 isolate->heap()->new_space()->
5534 template ShrinkStringAtAllocationBoundary<StringType>(
5535 new_string, final_length);
5536 return new_string;
5537}
5538
5539
5540RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5541 NoHandleAllocation ha;
5542 ASSERT(args.length() == 1);
5543 CONVERT_CHECKED(JSArray, array, args[0]);
5544
5545 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5546 FixedArray* elements = FixedArray::cast(array->elements());
5547 int n = elements->length();
5548 bool ascii = true;
5549 int total_length = 0;
5550
5551 for (int i = 0; i < n; i++) {
5552 Object* elt = elements->get(i);
5553 if (!elt->IsString()) return isolate->heap()->undefined_value();
5554 String* element = String::cast(elt);
5555 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5556 total_length += element->length();
5557 if (ascii && element->IsTwoByteRepresentation()) {
5558 ascii = false;
5559 }
5560 }
5561
5562 int worst_case_length =
5563 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5564 + total_length * kJsonQuoteWorstCaseBlowup;
5565
5566 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5567 return isolate->heap()->undefined_value();
5568 }
5569
5570 if (ascii) {
5571 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5572 elements,
5573 worst_case_length);
5574 } else {
5575 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5576 elements,
5577 worst_case_length);
5578 }
5579}
5580
5581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005582RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 NoHandleAllocation ha;
5584
5585 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005586 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005588 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589
lrn@chromium.org25156de2010-04-06 13:10:27 +00005590 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005591 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593}
5594
5595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005596RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 NoHandleAllocation ha;
5598 CONVERT_CHECKED(String, str, args[0]);
5599
5600 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005601 double value = StringToDouble(isolate->unicode_cache(),
5602 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603
5604 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005606}
5607
5608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005610MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005611 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005612 String* s,
5613 int length,
5614 int input_string_length,
5615 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005616 // We try this twice, once with the assumption that the result is no longer
5617 // than the input and, if that assumption breaks, again with the exact
5618 // length. This may not be pretty, but it is nicer than what was here before
5619 // and I hereby claim my vaffel-is.
5620 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005621 // Allocate the resulting string.
5622 //
5623 // NOTE: This assumes that the upper/lower case of an ascii
5624 // character is also ascii. This is currently the case, but it
5625 // might break in the future if we implement more context and locale
5626 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005627 Object* o;
5628 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 ? isolate->heap()->AllocateRawAsciiString(length)
5630 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005631 if (!maybe_o->ToObject(&o)) return maybe_o;
5632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633 String* result = String::cast(o);
5634 bool has_changed_character = false;
5635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005636 // Convert all characters to upper case, assuming that they will fit
5637 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638 Access<StringInputBuffer> buffer(
5639 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005641 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 // We can assume that the string is not empty
5643 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005644 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005645 bool has_next = buffer->has_more();
5646 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 int char_length = mapping->get(current, next, chars);
5648 if (char_length == 0) {
5649 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005650 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 i++;
5652 } else if (char_length == 1) {
5653 // Common case: converting the letter resulted in one character.
5654 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005655 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005656 has_changed_character = true;
5657 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005658 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659 // We've assumed that the result would be as long as the
5660 // input but here is a character that converts to several
5661 // characters. No matter, we calculate the exact length
5662 // of the result and try the whole thing again.
5663 //
5664 // Note that this leaves room for optimization. We could just
5665 // memcpy what we already have to the result string. Also,
5666 // the result string is the last object allocated we could
5667 // "realloc" it and probably, in the vast majority of cases,
5668 // extend the existing string to be able to hold the full
5669 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005670 int next_length = 0;
5671 if (has_next) {
5672 next_length = mapping->get(next, 0, chars);
5673 if (next_length == 0) next_length = 1;
5674 }
5675 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676 while (buffer->has_more()) {
5677 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005678 // NOTE: we use 0 as the next character here because, while
5679 // the next character may affect what a character converts to,
5680 // it does not in any case affect the length of what it convert
5681 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682 int char_length = mapping->get(current, 0, chars);
5683 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005684 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005685 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005687 return Failure::OutOfMemoryException();
5688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005690 // Try again with the real length.
5691 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005692 } else {
5693 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005694 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695 i++;
5696 }
5697 has_changed_character = true;
5698 }
5699 current = next;
5700 }
5701 if (has_changed_character) {
5702 return result;
5703 } else {
5704 // If we didn't actually change anything in doing the conversion
5705 // we simple return the result and let the converted string
5706 // become garbage; there is no reason to keep two identical strings
5707 // alive.
5708 return s;
5709 }
5710}
5711
5712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713namespace {
5714
lrn@chromium.org303ada72010-10-27 09:33:13 +00005715static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5716
5717
5718// Given a word and two range boundaries returns a word with high bit
5719// set in every byte iff the corresponding input byte was strictly in
5720// the range (m, n). All the other bits in the result are cleared.
5721// This function is only useful when it can be inlined and the
5722// boundaries are statically known.
5723// Requires: all bytes in the input word and the boundaries must be
5724// ascii (less than 0x7F).
5725static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5726 // Every byte in an ascii string is less than or equal to 0x7F.
5727 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5728 // Use strict inequalities since in edge cases the function could be
5729 // further simplified.
5730 ASSERT(0 < m && m < n && n < 0x7F);
5731 // Has high bit set in every w byte less than n.
5732 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5733 // Has high bit set in every w byte greater than m.
5734 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5735 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5736}
5737
5738
5739enum AsciiCaseConversion {
5740 ASCII_TO_LOWER,
5741 ASCII_TO_UPPER
5742};
5743
5744
5745template <AsciiCaseConversion dir>
5746struct FastAsciiConverter {
5747 static bool Convert(char* dst, char* src, int length) {
5748#ifdef DEBUG
5749 char* saved_dst = dst;
5750 char* saved_src = src;
5751#endif
5752 // We rely on the distance between upper and lower case letters
5753 // being a known power of 2.
5754 ASSERT('a' - 'A' == (1 << 5));
5755 // Boundaries for the range of input characters than require conversion.
5756 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5757 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5758 bool changed = false;
5759 char* const limit = src + length;
5760#ifdef V8_HOST_CAN_READ_UNALIGNED
5761 // Process the prefix of the input that requires no conversion one
5762 // (machine) word at a time.
5763 while (src <= limit - sizeof(uintptr_t)) {
5764 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5765 if (AsciiRangeMask(w, lo, hi) != 0) {
5766 changed = true;
5767 break;
5768 }
5769 *reinterpret_cast<uintptr_t*>(dst) = w;
5770 src += sizeof(uintptr_t);
5771 dst += sizeof(uintptr_t);
5772 }
5773 // Process the remainder of the input performing conversion when
5774 // required one word at a time.
5775 while (src <= limit - sizeof(uintptr_t)) {
5776 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5777 uintptr_t m = AsciiRangeMask(w, lo, hi);
5778 // The mask has high (7th) bit set in every byte that needs
5779 // conversion and we know that the distance between cases is
5780 // 1 << 5.
5781 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5782 src += sizeof(uintptr_t);
5783 dst += sizeof(uintptr_t);
5784 }
5785#endif
5786 // Process the last few bytes of the input (or the whole input if
5787 // unaligned access is not supported).
5788 while (src < limit) {
5789 char c = *src;
5790 if (lo < c && c < hi) {
5791 c ^= (1 << 5);
5792 changed = true;
5793 }
5794 *dst = c;
5795 ++src;
5796 ++dst;
5797 }
5798#ifdef DEBUG
5799 CheckConvert(saved_dst, saved_src, length, changed);
5800#endif
5801 return changed;
5802 }
5803
5804#ifdef DEBUG
5805 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5806 bool expected_changed = false;
5807 for (int i = 0; i < length; i++) {
5808 if (dst[i] == src[i]) continue;
5809 expected_changed = true;
5810 if (dir == ASCII_TO_LOWER) {
5811 ASSERT('A' <= src[i] && src[i] <= 'Z');
5812 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5813 } else {
5814 ASSERT(dir == ASCII_TO_UPPER);
5815 ASSERT('a' <= src[i] && src[i] <= 'z');
5816 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5817 }
5818 }
5819 ASSERT(expected_changed == changed);
5820 }
5821#endif
5822};
5823
5824
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005825struct ToLowerTraits {
5826 typedef unibrow::ToLowercase UnibrowConverter;
5827
lrn@chromium.org303ada72010-10-27 09:33:13 +00005828 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005829};
5830
5831
5832struct ToUpperTraits {
5833 typedef unibrow::ToUppercase UnibrowConverter;
5834
lrn@chromium.org303ada72010-10-27 09:33:13 +00005835 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005836};
5837
5838} // namespace
5839
5840
5841template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005842MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005843 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005845 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005847 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005848 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005849
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005850 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005851 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005852 if (length == 0) return s;
5853
5854 // Simpler handling of ascii strings.
5855 //
5856 // NOTE: This assumes that the upper/lower case of an ascii
5857 // character is also ascii. This is currently the case, but it
5858 // might break in the future if we implement more context and locale
5859 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005860 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005861 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005863 if (!maybe_o->ToObject(&o)) return maybe_o;
5864 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005866 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005867 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005868 return has_changed_character ? result : s;
5869 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005870
lrn@chromium.org303ada72010-10-27 09:33:13 +00005871 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 { MaybeObject* maybe_answer =
5873 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005874 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5875 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005876 if (answer->IsSmi()) {
5877 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005878 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 ConvertCaseHelper(isolate,
5880 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005881 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5882 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005883 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005884 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005885}
5886
5887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005888RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005889 return ConvertCase<ToLowerTraits>(
5890 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005895 return ConvertCase<ToUpperTraits>(
5896 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897}
5898
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005899
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005900static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5901 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5902}
5903
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005905RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 3);
5908
5909 CONVERT_CHECKED(String, s, args[0]);
5910 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5911 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5912
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005913 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005914 int length = s->length();
5915
5916 int left = 0;
5917 if (trimLeft) {
5918 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5919 left++;
5920 }
5921 }
5922
5923 int right = length;
5924 if (trimRight) {
5925 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5926 right--;
5927 }
5928 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005929 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005930}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005932
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005933void FindAsciiStringIndices(Vector<const char> subject,
5934 char pattern,
5935 ZoneList<int>* indices,
5936 unsigned int limit) {
5937 ASSERT(limit > 0);
5938 // Collect indices of pattern in subject using memchr.
5939 // Stop after finding at most limit values.
5940 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5941 const char* subject_end = subject_start + subject.length();
5942 const char* pos = subject_start;
5943 while (limit > 0) {
5944 pos = reinterpret_cast<const char*>(
5945 memchr(pos, pattern, subject_end - pos));
5946 if (pos == NULL) return;
5947 indices->Add(static_cast<int>(pos - subject_start));
5948 pos++;
5949 limit--;
5950 }
5951}
5952
5953
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005954template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005955void FindStringIndices(Isolate* isolate,
5956 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005957 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005958 ZoneList<int>* indices,
5959 unsigned int limit) {
5960 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005961 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005962 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005963 int pattern_length = pattern.length();
5964 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005965 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005966 while (limit > 0) {
5967 index = search.Search(subject, index);
5968 if (index < 0) return;
5969 indices->Add(index);
5970 index += pattern_length;
5971 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005972 }
5973}
5974
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005976RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005977 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005979 CONVERT_ARG_CHECKED(String, subject, 0);
5980 CONVERT_ARG_CHECKED(String, pattern, 1);
5981 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5982
5983 int subject_length = subject->length();
5984 int pattern_length = pattern->length();
5985 RUNTIME_ASSERT(pattern_length > 0);
5986
5987 // The limit can be very large (0xffffffffu), but since the pattern
5988 // isn't empty, we can never create more parts than ~half the length
5989 // of the subject.
5990
5991 if (!subject->IsFlat()) FlattenString(subject);
5992
5993 static const int kMaxInitialListCapacity = 16;
5994
danno@chromium.org40cb8782011-05-25 07:58:50 +00005995 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005996
5997 // Find (up to limit) indices of separator and end-of-string in subject
5998 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5999 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006000 if (!pattern->IsFlat()) FlattenString(pattern);
6001
6002 // No allocation block.
6003 {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006004 AssertNoAllocation no_gc;
6005 String::FlatContent subject_content = subject->GetFlatContent();
6006 String::FlatContent pattern_content = pattern->GetFlatContent();
6007 ASSERT(subject_content.IsFlat());
6008 ASSERT(pattern_content.IsFlat());
6009 if (subject_content.IsAscii()) {
6010 Vector<const char> subject_vector = subject_content.ToAsciiVector();
6011 if (pattern_content.IsAscii()) {
6012 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006013 if (pattern_vector.length() == 1) {
6014 FindAsciiStringIndices(subject_vector,
6015 pattern_vector[0],
6016 &indices,
6017 limit);
6018 } else {
6019 FindStringIndices(isolate,
6020 subject_vector,
6021 pattern_vector,
6022 &indices,
6023 limit);
6024 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006025 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006026 FindStringIndices(isolate,
6027 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006028 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006029 &indices,
6030 limit);
6031 }
6032 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006033 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006034 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006035 FindStringIndices(isolate,
6036 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006037 pattern_content.ToAsciiVector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006038 &indices,
6039 limit);
6040 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 FindStringIndices(isolate,
6042 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006043 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006044 &indices,
6045 limit);
6046 }
6047 }
6048 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006049
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006050 if (static_cast<uint32_t>(indices.length()) < limit) {
6051 indices.Add(subject_length);
6052 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006053
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006054 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006055
6056 // Create JSArray of substrings separated by separator.
6057 int part_count = indices.length();
6058
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006059 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006060 result->set_length(Smi::FromInt(part_count));
6061
6062 ASSERT(result->HasFastElements());
6063
6064 if (part_count == 1 && indices.at(0) == subject_length) {
6065 FixedArray::cast(result->elements())->set(0, *subject);
6066 return *result;
6067 }
6068
6069 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6070 int part_start = 0;
6071 for (int i = 0; i < part_count; i++) {
6072 HandleScope local_loop_handle;
6073 int part_end = indices.at(i);
6074 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006075 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006076 elements->set(i, *substring);
6077 part_start = part_end + pattern_length;
6078 }
6079
6080 return *result;
6081}
6082
6083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084// Copies ascii characters to the given fixed array looking up
6085// one-char strings in the cache. Gives up on the first char that is
6086// not in the cache and fills the remainder with smi zeros. Returns
6087// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088static int CopyCachedAsciiCharsToArray(Heap* heap,
6089 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006090 FixedArray* elements,
6091 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006092 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093 FixedArray* ascii_cache = heap->single_character_string_cache();
6094 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006095 int i;
6096 for (i = 0; i < length; ++i) {
6097 Object* value = ascii_cache->get(chars[i]);
6098 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006100 elements->set(i, value, SKIP_WRITE_BARRIER);
6101 }
6102 if (i < length) {
6103 ASSERT(Smi::FromInt(0) == 0);
6104 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6105 }
6106#ifdef DEBUG
6107 for (int j = 0; j < length; ++j) {
6108 Object* element = elements->get(j);
6109 ASSERT(element == Smi::FromInt(0) ||
6110 (element->IsString() && String::cast(element)->LooksValid()));
6111 }
6112#endif
6113 return i;
6114}
6115
6116
6117// Converts a String to JSArray.
6118// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006119RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006121 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006122 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006123 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006124
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006125 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006126 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006127
6128 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006129 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006130 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006131 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006132 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006133 { MaybeObject* maybe_obj =
6134 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006135 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6136 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006138 String::FlatContent content = s->GetFlatContent();
6139 if (content.IsAscii()) {
6140 Vector<const char> chars = content.ToAsciiVector();
6141 // Note, this will initialize all elements (not only the prefix)
6142 // to prevent GC from seeing partially initialized array.
6143 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6144 chars.start(),
6145 *elements,
6146 length);
6147 } else {
6148 MemsetPointer(elements->data_start(),
6149 isolate->heap()->undefined_value(),
6150 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006151 }
6152 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006153 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006154 }
6155 for (int i = position; i < length; ++i) {
6156 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6157 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006158 }
6159
6160#ifdef DEBUG
6161 for (int i = 0; i < length; ++i) {
6162 ASSERT(String::cast(elements->get(i))->length() == 1);
6163 }
6164#endif
6165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006166 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167}
6168
6169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006170RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006171 NoHandleAllocation ha;
6172 ASSERT(args.length() == 1);
6173 CONVERT_CHECKED(String, value, args[0]);
6174 return value->ToObject();
6175}
6176
6177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006178bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006179 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006180 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006181 return char_length == 0;
6182}
6183
6184
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006185RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186 NoHandleAllocation ha;
6187 ASSERT(args.length() == 1);
6188
6189 Object* number = args[0];
6190 RUNTIME_ASSERT(number->IsNumber());
6191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193}
6194
6195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006196RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006197 NoHandleAllocation ha;
6198 ASSERT(args.length() == 1);
6199
6200 Object* number = args[0];
6201 RUNTIME_ASSERT(number->IsNumber());
6202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006203 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006204}
6205
6206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006207RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208 NoHandleAllocation ha;
6209 ASSERT(args.length() == 1);
6210
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006211 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006212
6213 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6214 if (number > 0 && number <= Smi::kMaxValue) {
6215 return Smi::FromInt(static_cast<int>(number));
6216 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006217 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006218}
6219
6220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006221RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006222 NoHandleAllocation ha;
6223 ASSERT(args.length() == 1);
6224
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006225 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006226
6227 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6228 if (number > 0 && number <= Smi::kMaxValue) {
6229 return Smi::FromInt(static_cast<int>(number));
6230 }
6231
6232 double double_value = DoubleToInteger(number);
6233 // Map both -0 and +0 to +0.
6234 if (double_value == 0) double_value = 0;
6235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006237}
6238
6239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 NoHandleAllocation ha;
6242 ASSERT(args.length() == 1);
6243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006245 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246}
6247
6248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006249RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 NoHandleAllocation ha;
6251 ASSERT(args.length() == 1);
6252
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006253 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254
6255 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6256 if (number > 0 && number <= Smi::kMaxValue) {
6257 return Smi::FromInt(static_cast<int>(number));
6258 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260}
6261
6262
ager@chromium.org870a0b62008-11-04 11:43:05 +00006263// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6264// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006265RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006266 NoHandleAllocation ha;
6267 ASSERT(args.length() == 1);
6268
6269 Object* obj = args[0];
6270 if (obj->IsSmi()) {
6271 return obj;
6272 }
6273 if (obj->IsHeapNumber()) {
6274 double value = HeapNumber::cast(obj)->value();
6275 int int_value = FastD2I(value);
6276 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6277 return Smi::FromInt(int_value);
6278 }
6279 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006280 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006281}
6282
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006287 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006288}
6289
6290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006291RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 NoHandleAllocation ha;
6293 ASSERT(args.length() == 2);
6294
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006295 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6296 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006297 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298}
6299
6300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006301RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 NoHandleAllocation ha;
6303 ASSERT(args.length() == 2);
6304
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006305 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6306 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006307 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308}
6309
6310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006311RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 NoHandleAllocation ha;
6313 ASSERT(args.length() == 2);
6314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6316 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006317 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318}
6319
6320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006321RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006322 NoHandleAllocation ha;
6323 ASSERT(args.length() == 1);
6324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327}
6328
6329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006330RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 0);
6333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006334 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006335}
6336
6337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006338RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339 NoHandleAllocation ha;
6340 ASSERT(args.length() == 2);
6341
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006342 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6343 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345}
6346
6347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006348RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349 NoHandleAllocation ha;
6350 ASSERT(args.length() == 2);
6351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6353 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006354
ager@chromium.org3811b432009-10-28 14:53:37 +00006355 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006356 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006357 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358}
6359
6360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 NoHandleAllocation ha;
6363 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006364 CONVERT_CHECKED(String, str1, args[0]);
6365 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006366 isolate->counters()->string_add_runtime()->Increment();
6367 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368}
6369
6370
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006371template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006372static inline void StringBuilderConcatHelper(String* special,
6373 sinkchar* sink,
6374 FixedArray* fixed_array,
6375 int array_length) {
6376 int position = 0;
6377 for (int i = 0; i < array_length; i++) {
6378 Object* element = fixed_array->get(i);
6379 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006380 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006381 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006382 int pos;
6383 int len;
6384 if (encoded_slice > 0) {
6385 // Position and length encoded in one smi.
6386 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6387 len = StringBuilderSubstringLength::decode(encoded_slice);
6388 } else {
6389 // Position and length encoded in two smis.
6390 Object* obj = fixed_array->get(++i);
6391 ASSERT(obj->IsSmi());
6392 pos = Smi::cast(obj)->value();
6393 len = -encoded_slice;
6394 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006395 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006396 sink + position,
6397 pos,
6398 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006399 position += len;
6400 } else {
6401 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006402 int element_length = string->length();
6403 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006404 position += element_length;
6405 }
6406 }
6407}
6408
6409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006410RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006411 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006412 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006414 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006415 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006416 return Failure::OutOfMemoryException();
6417 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006418 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006419 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006420
6421 // This assumption is used by the slice encoding in one or two smis.
6422 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6423
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006424 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006427 }
6428 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006429 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006430 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006431 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432
6433 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006434 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435 } else if (array_length == 1) {
6436 Object* first = fixed_array->get(0);
6437 if (first->IsString()) return first;
6438 }
6439
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006440 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 int position = 0;
6442 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006443 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444 Object* elt = fixed_array->get(i);
6445 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006446 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006447 int smi_value = Smi::cast(elt)->value();
6448 int pos;
6449 int len;
6450 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006451 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006452 pos = StringBuilderSubstringPosition::decode(smi_value);
6453 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006454 } else {
6455 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006456 len = -smi_value;
6457 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006458 i++;
6459 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006461 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006462 Object* next_smi = fixed_array->get(i);
6463 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006465 }
6466 pos = Smi::cast(next_smi)->value();
6467 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006471 ASSERT(pos >= 0);
6472 ASSERT(len >= 0);
6473 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006475 }
6476 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477 } else if (elt->IsString()) {
6478 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006479 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006480 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006481 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006483 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006486 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006487 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006489 return Failure::OutOfMemoryException();
6490 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006491 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 }
6493
6494 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006498 { MaybeObject* maybe_object =
6499 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006500 if (!maybe_object->ToObject(&object)) return maybe_object;
6501 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006502 SeqAsciiString* answer = SeqAsciiString::cast(object);
6503 StringBuilderConcatHelper(special,
6504 answer->GetChars(),
6505 fixed_array,
6506 array_length);
6507 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 { MaybeObject* maybe_object =
6510 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006511 if (!maybe_object->ToObject(&object)) return maybe_object;
6512 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006513 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6514 StringBuilderConcatHelper(special,
6515 answer->GetChars(),
6516 fixed_array,
6517 array_length);
6518 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520}
6521
6522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006523RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006524 NoHandleAllocation ha;
6525 ASSERT(args.length() == 3);
6526 CONVERT_CHECKED(JSArray, array, args[0]);
6527 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006529 return Failure::OutOfMemoryException();
6530 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006531 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006532 CONVERT_CHECKED(String, separator, args[2]);
6533
6534 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006535 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006536 }
6537 FixedArray* fixed_array = FixedArray::cast(array->elements());
6538 if (fixed_array->length() < array_length) {
6539 array_length = fixed_array->length();
6540 }
6541
6542 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006544 } else if (array_length == 1) {
6545 Object* first = fixed_array->get(0);
6546 if (first->IsString()) return first;
6547 }
6548
6549 int separator_length = separator->length();
6550 int max_nof_separators =
6551 (String::kMaxLength + separator_length - 1) / separator_length;
6552 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006553 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006554 return Failure::OutOfMemoryException();
6555 }
6556 int length = (array_length - 1) * separator_length;
6557 for (int i = 0; i < array_length; i++) {
6558 Object* element_obj = fixed_array->get(i);
6559 if (!element_obj->IsString()) {
6560 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006562 }
6563 String* element = String::cast(element_obj);
6564 int increment = element->length();
6565 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006566 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006567 return Failure::OutOfMemoryException();
6568 }
6569 length += increment;
6570 }
6571
6572 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006573 { MaybeObject* maybe_object =
6574 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006575 if (!maybe_object->ToObject(&object)) return maybe_object;
6576 }
6577 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6578
6579 uc16* sink = answer->GetChars();
6580#ifdef DEBUG
6581 uc16* end = sink + length;
6582#endif
6583
6584 String* first = String::cast(fixed_array->get(0));
6585 int first_length = first->length();
6586 String::WriteToFlat(first, sink, 0, first_length);
6587 sink += first_length;
6588
6589 for (int i = 1; i < array_length; i++) {
6590 ASSERT(sink + separator_length <= end);
6591 String::WriteToFlat(separator, sink, 0, separator_length);
6592 sink += separator_length;
6593
6594 String* element = String::cast(fixed_array->get(i));
6595 int element_length = element->length();
6596 ASSERT(sink + element_length <= end);
6597 String::WriteToFlat(element, sink, 0, element_length);
6598 sink += element_length;
6599 }
6600 ASSERT(sink == end);
6601
6602 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6603 return answer;
6604}
6605
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006606template <typename Char>
6607static void JoinSparseArrayWithSeparator(FixedArray* elements,
6608 int elements_length,
6609 uint32_t array_length,
6610 String* separator,
6611 Vector<Char> buffer) {
6612 int previous_separator_position = 0;
6613 int separator_length = separator->length();
6614 int cursor = 0;
6615 for (int i = 0; i < elements_length; i += 2) {
6616 int position = NumberToInt32(elements->get(i));
6617 String* string = String::cast(elements->get(i + 1));
6618 int string_length = string->length();
6619 if (string->length() > 0) {
6620 while (previous_separator_position < position) {
6621 String::WriteToFlat<Char>(separator, &buffer[cursor],
6622 0, separator_length);
6623 cursor += separator_length;
6624 previous_separator_position++;
6625 }
6626 String::WriteToFlat<Char>(string, &buffer[cursor],
6627 0, string_length);
6628 cursor += string->length();
6629 }
6630 }
6631 if (separator_length > 0) {
6632 // Array length must be representable as a signed 32-bit number,
6633 // otherwise the total string length would have been too large.
6634 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6635 int last_array_index = static_cast<int>(array_length - 1);
6636 while (previous_separator_position < last_array_index) {
6637 String::WriteToFlat<Char>(separator, &buffer[cursor],
6638 0, separator_length);
6639 cursor += separator_length;
6640 previous_separator_position++;
6641 }
6642 }
6643 ASSERT(cursor <= buffer.length());
6644}
6645
6646
6647RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6648 NoHandleAllocation ha;
6649 ASSERT(args.length() == 3);
6650 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6651 RUNTIME_ASSERT(elements_array->HasFastElements());
6652 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6653 CONVERT_CHECKED(String, separator, args[2]);
6654 // elements_array is fast-mode JSarray of alternating positions
6655 // (increasing order) and strings.
6656 // array_length is length of original array (used to add separators);
6657 // separator is string to put between elements. Assumed to be non-empty.
6658
6659 // Find total length of join result.
6660 int string_length = 0;
6661 bool is_ascii = true;
6662 int max_string_length = SeqAsciiString::kMaxLength;
6663 bool overflow = false;
6664 CONVERT_NUMBER_CHECKED(int, elements_length,
6665 Int32, elements_array->length());
6666 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6667 FixedArray* elements = FixedArray::cast(elements_array->elements());
6668 for (int i = 0; i < elements_length; i += 2) {
6669 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6670 CONVERT_CHECKED(String, string, elements->get(i + 1));
6671 int length = string->length();
6672 if (is_ascii && !string->IsAsciiRepresentation()) {
6673 is_ascii = false;
6674 max_string_length = SeqTwoByteString::kMaxLength;
6675 }
6676 if (length > max_string_length ||
6677 max_string_length - length < string_length) {
6678 overflow = true;
6679 break;
6680 }
6681 string_length += length;
6682 }
6683 int separator_length = separator->length();
6684 if (!overflow && separator_length > 0) {
6685 if (array_length <= 0x7fffffffu) {
6686 int separator_count = static_cast<int>(array_length) - 1;
6687 int remaining_length = max_string_length - string_length;
6688 if ((remaining_length / separator_length) >= separator_count) {
6689 string_length += separator_length * (array_length - 1);
6690 } else {
6691 // Not room for the separators within the maximal string length.
6692 overflow = true;
6693 }
6694 } else {
6695 // Nonempty separator and at least 2^31-1 separators necessary
6696 // means that the string is too large to create.
6697 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6698 overflow = true;
6699 }
6700 }
6701 if (overflow) {
6702 // Throw OutOfMemory exception for creating too large a string.
6703 V8::FatalProcessOutOfMemory("Array join result too large.");
6704 }
6705
6706 if (is_ascii) {
6707 MaybeObject* result_allocation =
6708 isolate->heap()->AllocateRawAsciiString(string_length);
6709 if (result_allocation->IsFailure()) return result_allocation;
6710 SeqAsciiString* result_string =
6711 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6712 JoinSparseArrayWithSeparator<char>(elements,
6713 elements_length,
6714 array_length,
6715 separator,
6716 Vector<char>(result_string->GetChars(),
6717 string_length));
6718 return result_string;
6719 } else {
6720 MaybeObject* result_allocation =
6721 isolate->heap()->AllocateRawTwoByteString(string_length);
6722 if (result_allocation->IsFailure()) return result_allocation;
6723 SeqTwoByteString* result_string =
6724 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6725 JoinSparseArrayWithSeparator<uc16>(elements,
6726 elements_length,
6727 array_length,
6728 separator,
6729 Vector<uc16>(result_string->GetChars(),
6730 string_length));
6731 return result_string;
6732 }
6733}
6734
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006736RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 NoHandleAllocation ha;
6738 ASSERT(args.length() == 2);
6739
6740 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6741 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743}
6744
6745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006746RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 NoHandleAllocation ha;
6748 ASSERT(args.length() == 2);
6749
6750 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6751 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 NoHandleAllocation ha;
6758 ASSERT(args.length() == 2);
6759
6760 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6761 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763}
6764
6765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006766RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 NoHandleAllocation ha;
6768 ASSERT(args.length() == 1);
6769
6770 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772}
6773
6774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006775RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 NoHandleAllocation ha;
6777 ASSERT(args.length() == 2);
6778
6779 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6780 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782}
6783
6784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006785RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 NoHandleAllocation ha;
6787 ASSERT(args.length() == 2);
6788
6789 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6790 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006791 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792}
6793
6794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006795RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 NoHandleAllocation ha;
6797 ASSERT(args.length() == 2);
6798
6799 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6800 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802}
6803
6804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006805RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806 NoHandleAllocation ha;
6807 ASSERT(args.length() == 2);
6808
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006809 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6810 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6812 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6813 if (x == y) return Smi::FromInt(EQUAL);
6814 Object* result;
6815 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6816 result = Smi::FromInt(EQUAL);
6817 } else {
6818 result = Smi::FromInt(NOT_EQUAL);
6819 }
6820 return result;
6821}
6822
6823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006824RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 NoHandleAllocation ha;
6826 ASSERT(args.length() == 2);
6827
6828 CONVERT_CHECKED(String, x, args[0]);
6829 CONVERT_CHECKED(String, y, args[1]);
6830
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006831 bool not_equal = !x->Equals(y);
6832 // This is slightly convoluted because the value that signifies
6833 // equality is 0 and inequality is 1 so we have to negate the result
6834 // from String::Equals.
6835 ASSERT(not_equal == 0 || not_equal == 1);
6836 STATIC_CHECK(EQUAL == 0);
6837 STATIC_CHECK(NOT_EQUAL == 1);
6838 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839}
6840
6841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006842RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843 NoHandleAllocation ha;
6844 ASSERT(args.length() == 3);
6845
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006846 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6847 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848 if (isnan(x) || isnan(y)) return args[2];
6849 if (x == y) return Smi::FromInt(EQUAL);
6850 if (isless(x, y)) return Smi::FromInt(LESS);
6851 return Smi::FromInt(GREATER);
6852}
6853
6854
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006855// Compare two Smis as if they were converted to strings and then
6856// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006857RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006858 NoHandleAllocation ha;
6859 ASSERT(args.length() == 2);
6860
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006861 // Extract the integer values from the Smis.
6862 CONVERT_CHECKED(Smi, x, args[0]);
6863 CONVERT_CHECKED(Smi, y, args[1]);
6864 int x_value = x->value();
6865 int y_value = y->value();
6866
6867 // If the integers are equal so are the string representations.
6868 if (x_value == y_value) return Smi::FromInt(EQUAL);
6869
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006870 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006871 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006872 if (x_value == 0 || y_value == 0)
6873 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006874
ager@chromium.org32912102009-01-16 10:38:43 +00006875 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006876 // smallest because the char code of '-' is less than the char code
6877 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006878
6879 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6880 // architectures using 32-bit Smis.
6881 uint32_t x_scaled = x_value;
6882 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006883 if (x_value < 0 || y_value < 0) {
6884 if (y_value >= 0) return Smi::FromInt(LESS);
6885 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006886 x_scaled = -x_value;
6887 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006888 }
6889
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006890 static const uint32_t kPowersOf10[] = {
6891 1, 10, 100, 1000, 10*1000, 100*1000,
6892 1000*1000, 10*1000*1000, 100*1000*1000,
6893 1000*1000*1000
6894 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006896 // If the integers have the same number of decimal digits they can be
6897 // compared directly as the numeric order is the same as the
6898 // lexicographic order. If one integer has fewer digits, it is scaled
6899 // by some power of 10 to have the same number of digits as the longer
6900 // integer. If the scaled integers are equal it means the shorter
6901 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006903 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6904 int x_log2 = IntegerLog2(x_scaled);
6905 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6906 x_log10 -= x_scaled < kPowersOf10[x_log10];
6907
6908 int y_log2 = IntegerLog2(y_scaled);
6909 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6910 y_log10 -= y_scaled < kPowersOf10[y_log10];
6911
6912 int tie = EQUAL;
6913
6914 if (x_log10 < y_log10) {
6915 // X has fewer digits. We would like to simply scale up X but that
6916 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6917 // be scaled up to 9_000_000_000. So we scale up by the next
6918 // smallest power and scale down Y to drop one digit. It is OK to
6919 // drop one digit from the longer integer since the final digit is
6920 // past the length of the shorter integer.
6921 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6922 y_scaled /= 10;
6923 tie = LESS;
6924 } else if (y_log10 < x_log10) {
6925 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6926 x_scaled /= 10;
6927 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006928 }
6929
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006930 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6931 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6932 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006933}
6934
6935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006936static Object* StringInputBufferCompare(RuntimeState* state,
6937 String* x,
6938 String* y) {
6939 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6940 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006941 bufx.Reset(x);
6942 bufy.Reset(y);
6943 while (bufx.has_more() && bufy.has_more()) {
6944 int d = bufx.GetNext() - bufy.GetNext();
6945 if (d < 0) return Smi::FromInt(LESS);
6946 else if (d > 0) return Smi::FromInt(GREATER);
6947 }
6948
6949 // x is (non-trivial) prefix of y:
6950 if (bufy.has_more()) return Smi::FromInt(LESS);
6951 // y is prefix of x:
6952 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6953}
6954
6955
6956static Object* FlatStringCompare(String* x, String* y) {
6957 ASSERT(x->IsFlat());
6958 ASSERT(y->IsFlat());
6959 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6960 int prefix_length = x->length();
6961 if (y->length() < prefix_length) {
6962 prefix_length = y->length();
6963 equal_prefix_result = Smi::FromInt(GREATER);
6964 } else if (y->length() > prefix_length) {
6965 equal_prefix_result = Smi::FromInt(LESS);
6966 }
6967 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006968 String::FlatContent x_content = x->GetFlatContent();
6969 String::FlatContent y_content = y->GetFlatContent();
6970 if (x_content.IsAscii()) {
6971 Vector<const char> x_chars = x_content.ToAsciiVector();
6972 if (y_content.IsAscii()) {
6973 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006974 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006975 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006976 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006977 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6978 }
6979 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006980 Vector<const uc16> x_chars = x_content.ToUC16Vector();
6981 if (y_content.IsAscii()) {
6982 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006983 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6984 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006985 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006986 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6987 }
6988 }
6989 Object* result;
6990 if (r == 0) {
6991 result = equal_prefix_result;
6992 } else {
6993 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6994 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006995 ASSERT(result ==
6996 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006997 return result;
6998}
6999
7000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007001RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002 NoHandleAllocation ha;
7003 ASSERT(args.length() == 2);
7004
7005 CONVERT_CHECKED(String, x, args[0]);
7006 CONVERT_CHECKED(String, y, args[1]);
7007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007008 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010 // A few fast case tests before we flatten.
7011 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007012 if (y->length() == 0) {
7013 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007015 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 return Smi::FromInt(LESS);
7017 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007018
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007019 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007020 if (d < 0) return Smi::FromInt(LESS);
7021 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022
lrn@chromium.org303ada72010-10-27 09:33:13 +00007023 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007025 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7026 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007028 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007031 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033}
7034
7035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007036RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 NoHandleAllocation ha;
7038 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007039 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007041 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007051 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007056RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057 NoHandleAllocation ha;
7058 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007061 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007062 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063}
7064
7065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066static const double kPiDividedBy4 = 0.78539816339744830962;
7067
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070 NoHandleAllocation ha;
7071 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007072 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007074 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7075 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007076 double result;
7077 if (isinf(x) && isinf(y)) {
7078 // Make sure that the result in case of two infinite arguments
7079 // is a multiple of Pi / 4. The sign of the result is determined
7080 // by the first argument (x) and the sign of the second argument
7081 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007082 int multiplier = (x < 0) ? -1 : 1;
7083 if (y < 0) multiplier *= 3;
7084 result = multiplier * kPiDividedBy4;
7085 } else {
7086 result = atan2(x, y);
7087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007088 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089}
7090
7091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007092RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 NoHandleAllocation ha;
7094 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007095 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007097 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007098 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007107 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007108 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109}
7110
7111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007112RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113 NoHandleAllocation ha;
7114 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007115 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007117 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007118 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119}
7120
7121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007122RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123 NoHandleAllocation ha;
7124 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007127 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007129}
7130
7131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007132RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 NoHandleAllocation ha;
7134 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007135 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007137 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007138 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007139}
7140
7141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007142RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 NoHandleAllocation ha;
7144 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007146
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007147 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007148
7149 // If the second argument is a smi, it is much faster to call the
7150 // custom powi() function than the generic pow().
7151 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007152 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007153 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007154 }
7155
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007156 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007157 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158}
7159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007160// Fast version of Math.pow if we know that y is not an integer and
7161// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007162RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007163 NoHandleAllocation ha;
7164 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007165 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7166 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007167 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007168 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007169 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007171 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007173 }
7174}
7175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007177RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178 NoHandleAllocation ha;
7179 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007181
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007182 if (!args[0]->IsHeapNumber()) {
7183 // Must be smi. Return the argument unchanged for all the other types
7184 // to make fuzz-natives test happy.
7185 return args[0];
7186 }
7187
7188 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7189
7190 double value = number->value();
7191 int exponent = number->get_exponent();
7192 int sign = number->get_sign();
7193
danno@chromium.org160a7b02011-04-18 15:51:38 +00007194 if (exponent < -1) {
7195 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7196 if (sign) return isolate->heap()->minus_zero_value();
7197 return Smi::FromInt(0);
7198 }
7199
7200 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7201 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7202 // agument holds for 32-bit smis).
7203 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007204 return Smi::FromInt(static_cast<int>(value + 0.5));
7205 }
7206
7207 // If the magnitude is big enough, there's no place for fraction part. If we
7208 // try to add 0.5 to this number, 1.0 will be added instead.
7209 if (exponent >= 52) {
7210 return number;
7211 }
7212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007214
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007215 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007217}
7218
7219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007220RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221 NoHandleAllocation ha;
7222 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007223 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007225 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007226 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007227}
7228
7229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007230RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007231 NoHandleAllocation ha;
7232 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007233 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007235 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007236 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237}
7238
7239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007240RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241 NoHandleAllocation ha;
7242 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007243 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007244
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007245 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007246 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007247}
7248
7249
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007250static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007251 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7252 181, 212, 243, 273, 304, 334};
7253 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7254 182, 213, 244, 274, 305, 335};
7255
7256 year += month / 12;
7257 month %= 12;
7258 if (month < 0) {
7259 year--;
7260 month += 12;
7261 }
7262
7263 ASSERT(month >= 0);
7264 ASSERT(month < 12);
7265
7266 // year_delta is an arbitrary number such that:
7267 // a) year_delta = -1 (mod 400)
7268 // b) year + year_delta > 0 for years in the range defined by
7269 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7270 // Jan 1 1970. This is required so that we don't run into integer
7271 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007272 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007273 // operations.
7274 static const int year_delta = 399999;
7275 static const int base_day = 365 * (1970 + year_delta) +
7276 (1970 + year_delta) / 4 -
7277 (1970 + year_delta) / 100 +
7278 (1970 + year_delta) / 400;
7279
7280 int year1 = year + year_delta;
7281 int day_from_year = 365 * year1 +
7282 year1 / 4 -
7283 year1 / 100 +
7284 year1 / 400 -
7285 base_day;
7286
7287 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007288 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007289 }
7290
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007291 return day_from_year + day_from_month_leap[month] + day - 1;
7292}
7293
7294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007295RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007296 NoHandleAllocation ha;
7297 ASSERT(args.length() == 3);
7298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007299 CONVERT_SMI_ARG_CHECKED(year, 0);
7300 CONVERT_SMI_ARG_CHECKED(month, 1);
7301 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007302
7303 return Smi::FromInt(MakeDay(year, month, date));
7304}
7305
7306
7307static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7308static const int kDaysIn4Years = 4 * 365 + 1;
7309static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7310static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7311static const int kDays1970to2000 = 30 * 365 + 7;
7312static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7313 kDays1970to2000;
7314static const int kYearsOffset = 400000;
7315
7316static const char kDayInYear[] = {
7317 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7318 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7319 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7320 22, 23, 24, 25, 26, 27, 28,
7321 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7322 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7323 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7324 22, 23, 24, 25, 26, 27, 28, 29, 30,
7325 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7326 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7328 22, 23, 24, 25, 26, 27, 28, 29, 30,
7329 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7330 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7332 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7333 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7334 22, 23, 24, 25, 26, 27, 28, 29, 30,
7335 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7336 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7337 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7338 22, 23, 24, 25, 26, 27, 28, 29, 30,
7339 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7340 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7341
7342 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7343 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7344 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7345 22, 23, 24, 25, 26, 27, 28,
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28, 29, 30,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7359 22, 23, 24, 25, 26, 27, 28, 29, 30,
7360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7363 22, 23, 24, 25, 26, 27, 28, 29, 30,
7364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7365 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7366
7367 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7368 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7369 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7370 22, 23, 24, 25, 26, 27, 28, 29,
7371 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7372 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7373 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7374 22, 23, 24, 25, 26, 27, 28, 29, 30,
7375 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7376 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7378 22, 23, 24, 25, 26, 27, 28, 29, 30,
7379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7380 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7383 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7384 22, 23, 24, 25, 26, 27, 28, 29, 30,
7385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7387 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7388 22, 23, 24, 25, 26, 27, 28, 29, 30,
7389 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7390 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7391
7392 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7393 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7394 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7395 22, 23, 24, 25, 26, 27, 28,
7396 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7397 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7398 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7399 22, 23, 24, 25, 26, 27, 28, 29, 30,
7400 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7401 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7403 22, 23, 24, 25, 26, 27, 28, 29, 30,
7404 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7405 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7406 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7407 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7408 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7409 22, 23, 24, 25, 26, 27, 28, 29, 30,
7410 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7411 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7412 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7413 22, 23, 24, 25, 26, 27, 28, 29, 30,
7414 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7415 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7416
7417static const char kMonthInYear[] = {
7418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7419 0, 0, 0, 0, 0, 0,
7420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7421 1, 1, 1,
7422 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7423 2, 2, 2, 2, 2, 2,
7424 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7425 3, 3, 3, 3, 3,
7426 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7427 4, 4, 4, 4, 4, 4,
7428 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7429 5, 5, 5, 5, 5,
7430 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7431 6, 6, 6, 6, 6, 6,
7432 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7433 7, 7, 7, 7, 7, 7,
7434 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7435 8, 8, 8, 8, 8,
7436 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7437 9, 9, 9, 9, 9, 9,
7438 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7439 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7440 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7441 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7442
7443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7444 0, 0, 0, 0, 0, 0,
7445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7446 1, 1, 1,
7447 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7448 2, 2, 2, 2, 2, 2,
7449 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7450 3, 3, 3, 3, 3,
7451 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7452 4, 4, 4, 4, 4, 4,
7453 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7454 5, 5, 5, 5, 5,
7455 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7456 6, 6, 6, 6, 6, 6,
7457 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7458 7, 7, 7, 7, 7, 7,
7459 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7460 8, 8, 8, 8, 8,
7461 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7462 9, 9, 9, 9, 9, 9,
7463 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7464 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7465 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7466 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7467
7468 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7469 0, 0, 0, 0, 0, 0,
7470 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7471 1, 1, 1, 1,
7472 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7473 2, 2, 2, 2, 2, 2,
7474 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7475 3, 3, 3, 3, 3,
7476 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7477 4, 4, 4, 4, 4, 4,
7478 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7479 5, 5, 5, 5, 5,
7480 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7481 6, 6, 6, 6, 6, 6,
7482 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7483 7, 7, 7, 7, 7, 7,
7484 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7485 8, 8, 8, 8, 8,
7486 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7487 9, 9, 9, 9, 9, 9,
7488 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7489 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7490 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7491 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7492
7493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7494 0, 0, 0, 0, 0, 0,
7495 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7496 1, 1, 1,
7497 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7498 2, 2, 2, 2, 2, 2,
7499 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7500 3, 3, 3, 3, 3,
7501 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7502 4, 4, 4, 4, 4, 4,
7503 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7504 5, 5, 5, 5, 5,
7505 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7506 6, 6, 6, 6, 6, 6,
7507 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7508 7, 7, 7, 7, 7, 7,
7509 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7510 8, 8, 8, 8, 8,
7511 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7512 9, 9, 9, 9, 9, 9,
7513 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7514 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7515 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7516 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7517
7518
7519// This function works for dates from 1970 to 2099.
7520static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007521 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007522#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007523 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007524#endif
7525
7526 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7527 date %= kDaysIn4Years;
7528
7529 month = kMonthInYear[date];
7530 day = kDayInYear[date];
7531
7532 ASSERT(MakeDay(year, month, day) == save_date);
7533}
7534
7535
7536static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007537 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007538#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007539 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007540#endif
7541
7542 date += kDaysOffset;
7543 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7544 date %= kDaysIn400Years;
7545
7546 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7547
7548 date--;
7549 int yd1 = date / kDaysIn100Years;
7550 date %= kDaysIn100Years;
7551 year += 100 * yd1;
7552
7553 date++;
7554 int yd2 = date / kDaysIn4Years;
7555 date %= kDaysIn4Years;
7556 year += 4 * yd2;
7557
7558 date--;
7559 int yd3 = date / 365;
7560 date %= 365;
7561 year += yd3;
7562
7563 bool is_leap = (!yd1 || yd2) && !yd3;
7564
7565 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007566 ASSERT(is_leap || (date >= 0));
7567 ASSERT((date < 365) || (is_leap && (date < 366)));
7568 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7569 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7570 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007571
7572 if (is_leap) {
7573 day = kDayInYear[2*365 + 1 + date];
7574 month = kMonthInYear[2*365 + 1 + date];
7575 } else {
7576 day = kDayInYear[date];
7577 month = kMonthInYear[date];
7578 }
7579
7580 ASSERT(MakeDay(year, month, day) == save_date);
7581}
7582
7583
7584static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007585 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007586 if (date >= 0 && date < 32 * kDaysIn4Years) {
7587 DateYMDFromTimeAfter1970(date, year, month, day);
7588 } else {
7589 DateYMDFromTimeSlow(date, year, month, day);
7590 }
7591}
7592
7593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007594RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007595 NoHandleAllocation ha;
7596 ASSERT(args.length() == 2);
7597
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007598 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007599 CONVERT_CHECKED(JSArray, res_array, args[1]);
7600
7601 int year, month, day;
7602 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 RUNTIME_ASSERT(res_array->elements()->map() ==
7605 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007606 FixedArray* elms = FixedArray::cast(res_array->elements());
7607 RUNTIME_ASSERT(elms->length() == 3);
7608
7609 elms->set(0, Smi::FromInt(year));
7610 elms->set(1, Smi::FromInt(month));
7611 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007613 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007614}
7615
7616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007617RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007618 HandleScope scope(isolate);
7619 ASSERT(args.length() == 3);
7620
7621 Handle<JSFunction> callee = args.at<JSFunction>(0);
7622 Object** parameters = reinterpret_cast<Object**>(args[1]);
7623 const int argument_count = Smi::cast(args[2])->value();
7624
7625 Handle<JSObject> result =
7626 isolate->factory()->NewArgumentsObject(callee, argument_count);
7627 // Allocate the elements if needed.
7628 int parameter_count = callee->shared()->formal_parameter_count();
7629 if (argument_count > 0) {
7630 if (parameter_count > 0) {
7631 int mapped_count = Min(argument_count, parameter_count);
7632 Handle<FixedArray> parameter_map =
7633 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7634 parameter_map->set_map(
7635 isolate->heap()->non_strict_arguments_elements_map());
7636
7637 Handle<Map> old_map(result->map());
7638 Handle<Map> new_map =
7639 isolate->factory()->CopyMapDropTransitions(old_map);
7640 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7641
7642 result->set_map(*new_map);
7643 result->set_elements(*parameter_map);
7644
7645 // Store the context and the arguments array at the beginning of the
7646 // parameter map.
7647 Handle<Context> context(isolate->context());
7648 Handle<FixedArray> arguments =
7649 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7650 parameter_map->set(0, *context);
7651 parameter_map->set(1, *arguments);
7652
7653 // Loop over the actual parameters backwards.
7654 int index = argument_count - 1;
7655 while (index >= mapped_count) {
7656 // These go directly in the arguments array and have no
7657 // corresponding slot in the parameter map.
7658 arguments->set(index, *(parameters - index - 1));
7659 --index;
7660 }
7661
7662 ScopeInfo<> scope_info(callee->shared()->scope_info());
7663 while (index >= 0) {
7664 // Detect duplicate names to the right in the parameter list.
7665 Handle<String> name = scope_info.parameter_name(index);
7666 int context_slot_count = scope_info.number_of_context_slots();
7667 bool duplicate = false;
7668 for (int j = index + 1; j < parameter_count; ++j) {
7669 if (scope_info.parameter_name(j).is_identical_to(name)) {
7670 duplicate = true;
7671 break;
7672 }
7673 }
7674
7675 if (duplicate) {
7676 // This goes directly in the arguments array with a hole in the
7677 // parameter map.
7678 arguments->set(index, *(parameters - index - 1));
7679 parameter_map->set_the_hole(index + 2);
7680 } else {
7681 // The context index goes in the parameter map with a hole in the
7682 // arguments array.
7683 int context_index = -1;
7684 for (int j = Context::MIN_CONTEXT_SLOTS;
7685 j < context_slot_count;
7686 ++j) {
7687 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7688 context_index = j;
7689 break;
7690 }
7691 }
7692 ASSERT(context_index >= 0);
7693 arguments->set_the_hole(index);
7694 parameter_map->set(index + 2, Smi::FromInt(context_index));
7695 }
7696
7697 --index;
7698 }
7699 } else {
7700 // If there is no aliasing, the arguments object elements are not
7701 // special in any way.
7702 Handle<FixedArray> elements =
7703 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7704 result->set_elements(*elements);
7705 for (int i = 0; i < argument_count; ++i) {
7706 elements->set(i, *(parameters - i - 1));
7707 }
7708 }
7709 }
7710 return *result;
7711}
7712
7713
7714RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007715 NoHandleAllocation ha;
7716 ASSERT(args.length() == 3);
7717
7718 JSFunction* callee = JSFunction::cast(args[0]);
7719 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007720 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007721
lrn@chromium.org303ada72010-10-27 09:33:13 +00007722 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007723 { MaybeObject* maybe_result =
7724 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007725 if (!maybe_result->ToObject(&result)) return maybe_result;
7726 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007727 // Allocate the elements if needed.
7728 if (length > 0) {
7729 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007730 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007731 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007732 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7733 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007734
7735 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007736 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007737 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007738 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007739
7740 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007741 for (int i = 0; i < length; i++) {
7742 array->set(i, *--parameters, mode);
7743 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007744 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007745 }
7746 return result;
7747}
7748
7749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007750RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007752 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007753 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007754 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007755 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007756
whesse@chromium.org7b260152011-06-20 15:33:18 +00007757 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007758 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007759 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007761 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7762 context,
7763 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764 return *result;
7765}
7766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007767
7768static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7769 int* total_argc) {
7770 // Find frame containing arguments passed to the caller.
7771 JavaScriptFrameIterator it;
7772 JavaScriptFrame* frame = it.frame();
7773 List<JSFunction*> functions(2);
7774 frame->GetFunctions(&functions);
7775 if (functions.length() > 1) {
7776 int inlined_frame_index = functions.length() - 1;
7777 JSFunction* inlined_function = functions[inlined_frame_index];
7778 int args_count = inlined_function->shared()->formal_parameter_count();
7779 ScopedVector<SlotRef> args_slots(args_count);
7780 SlotRef::ComputeSlotMappingForArguments(frame,
7781 inlined_frame_index,
7782 &args_slots);
7783
7784 *total_argc = bound_argc + args_count;
7785 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7786 for (int i = 0; i < args_count; i++) {
7787 Handle<Object> val = args_slots[i].GetValue();
7788 param_data[bound_argc + i] = val.location();
7789 }
7790 return param_data;
7791 } else {
7792 it.AdvanceToArgumentsFrame();
7793 frame = it.frame();
7794 int args_count = frame->ComputeParametersCount();
7795
7796 *total_argc = bound_argc + args_count;
7797 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7798 for (int i = 0; i < args_count; i++) {
7799 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7800 param_data[bound_argc + i] = val.location();
7801 }
7802 return param_data;
7803 }
7804}
7805
7806
7807RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007808 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007809 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007810 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007811 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007812
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007813 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007814 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007815 int bound_argc = 0;
7816 if (!args[1]->IsNull()) {
7817 CONVERT_ARG_CHECKED(JSArray, params, 1);
7818 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007819 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007820 bound_argc = Smi::cast(params->length())->value();
7821 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007823 int total_argc = 0;
7824 SmartPointer<Object**> param_data =
7825 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007826 for (int i = 0; i < bound_argc; i++) {
7827 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007828 param_data[i] = val.location();
7829 }
7830
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007831 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007832 Handle<Object> result =
7833 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007834 if (exception) {
7835 return Failure::Exception();
7836 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007837
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007838 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007839 return *result;
7840}
7841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007843static void TrySettingInlineConstructStub(Isolate* isolate,
7844 Handle<JSFunction> function) {
7845 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007846 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007848 }
7849 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007850 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007851 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007852 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007853 function->shared()->set_construct_stub(
7854 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007855 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007856 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007857}
7858
7859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007860RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007861 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 ASSERT(args.length() == 1);
7863
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007864 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007866 // If the constructor isn't a proper function we throw a type error.
7867 if (!constructor->IsJSFunction()) {
7868 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7869 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007870 isolate->factory()->NewTypeError("not_constructor", arguments);
7871 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007872 }
7873
7874 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007875
7876 // If function should not have prototype, construction is not allowed. In this
7877 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007878 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007879 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7880 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007881 isolate->factory()->NewTypeError("not_constructor", arguments);
7882 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007883 }
7884
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007885#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007886 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007887 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888 if (debug->StepInActive()) {
7889 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007890 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007891#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007893 if (function->has_initial_map()) {
7894 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007895 // The 'Function' function ignores the receiver object when
7896 // called using 'new' and creates a new JSFunction object that
7897 // is returned. The receiver object is only used for error
7898 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007899 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007900 // allocate JSFunctions since it does not properly initialize
7901 // the shared part of the function. Since the receiver is
7902 // ignored anyway, we use the global object as the receiver
7903 // instead of a new JSFunction object. This way, errors are
7904 // reported the same way whether or not 'Function' is called
7905 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 }
7909
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007910 // The function should be compiled for the optimization hints to be
7911 // available. We cannot use EnsureCompiled because that forces a
7912 // compilation through the shared function info which makes it
7913 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007914 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007915 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007916
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007917 if (!function->has_initial_map() &&
7918 shared->IsInobjectSlackTrackingInProgress()) {
7919 // The tracking is already in progress for another function. We can only
7920 // track one initial_map at a time, so we force the completion before the
7921 // function is called as a constructor for the first time.
7922 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007923 }
7924
7925 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7927 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007928 // Delay setting the stub if inobject slack tracking is in progress.
7929 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007931 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007933 isolate->counters()->constructed_objects()->Increment();
7934 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007935
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007936 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937}
7938
7939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007940RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007941 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007942 ASSERT(args.length() == 1);
7943
7944 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7945 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007946 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007949}
7950
7951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 ASSERT(args.length() == 1);
7955
7956 Handle<JSFunction> function = args.at<JSFunction>(0);
7957#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007958 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007959 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007960 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 PrintF("]\n");
7962 }
7963#endif
7964
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007965 // Compile the target function. Here we compile using CompileLazyInLoop in
7966 // order to get the optimized version. This helps code like delta-blue
7967 // that calls performance-critical routines through constructors. A
7968 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7969 // direct call. Since the in-loop tracking takes place through CallICs
7970 // this means that things called through constructors are never known to
7971 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007972 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007973 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 return Failure::Exception();
7975 }
7976
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007977 // All done. Return the compiled code.
7978 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007979 return function->code();
7980}
7981
7982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007983RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007984 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985 ASSERT(args.length() == 1);
7986 Handle<JSFunction> function = args.at<JSFunction>(0);
7987 // If the function is not optimizable or debugger is active continue using the
7988 // code from the full compiler.
7989 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007990 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007991 if (FLAG_trace_opt) {
7992 PrintF("[failed to optimize ");
7993 function->PrintName();
7994 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7995 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007996 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007997 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007998 function->ReplaceCode(function->shared()->code());
7999 return function->code();
8000 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008001 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008002 return function->code();
8003 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008004 if (FLAG_trace_opt) {
8005 PrintF("[failed to optimize ");
8006 function->PrintName();
8007 PrintF(": optimized compilation failed]\n");
8008 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008009 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008010 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008011}
8012
8013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008014RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008015 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008016 ASSERT(args.length() == 1);
8017 RUNTIME_ASSERT(args[0]->IsSmi());
8018 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008019 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008020 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8021 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008022 int frames = deoptimizer->output_count();
8023
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008024 deoptimizer->MaterializeHeapNumbers();
8025 delete deoptimizer;
8026
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008027 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008028 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008029 for (int i = 0; i < frames - 1; i++) it.Advance();
8030 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031
8032 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008033 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008034 Handle<Object> arguments;
8035 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008036 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037 if (arguments.is_null()) {
8038 // FunctionGetArguments can't throw an exception, so cast away the
8039 // doubt with an assert.
8040 arguments = Handle<Object>(
8041 Accessors::FunctionGetArguments(*function,
8042 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 ASSERT(*arguments != isolate->heap()->null_value());
8044 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008045 }
8046 frame->SetExpression(i, *arguments);
8047 }
8048 }
8049
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050 if (type == Deoptimizer::EAGER) {
8051 RUNTIME_ASSERT(function->IsOptimized());
8052 } else {
8053 RUNTIME_ASSERT(!function->IsOptimized());
8054 }
8055
8056 // Avoid doing too much work when running with --always-opt and keep
8057 // the optimized code around.
8058 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008059 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008060 }
8061
8062 // Count the number of optimized activations of the function.
8063 int activations = 0;
8064 while (!it.done()) {
8065 JavaScriptFrame* frame = it.frame();
8066 if (frame->is_optimized() && frame->function() == *function) {
8067 activations++;
8068 }
8069 it.Advance();
8070 }
8071
8072 // TODO(kasperl): For now, we cannot support removing the optimized
8073 // code when we have recursive invocations of the same function.
8074 if (activations == 0) {
8075 if (FLAG_trace_deopt) {
8076 PrintF("[removing optimized code for: ");
8077 function->PrintName();
8078 PrintF("]\n");
8079 }
8080 function->ReplaceCode(function->shared()->code());
8081 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008082 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008083}
8084
8085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008087 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008088 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008090}
8091
8092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008093RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008095 ASSERT(args.length() == 1);
8096 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008098
8099 Deoptimizer::DeoptimizeFunction(*function);
8100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008101 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008102}
8103
8104
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008105RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8106#if defined(USE_SIMULATOR)
8107 return isolate->heap()->true_value();
8108#else
8109 return isolate->heap()->false_value();
8110#endif
8111}
8112
8113
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008114RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8115 HandleScope scope(isolate);
8116 ASSERT(args.length() == 1);
8117 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8118 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8119 function->MarkForLazyRecompilation();
8120 return isolate->heap()->undefined_value();
8121}
8122
8123
lrn@chromium.org1c092762011-05-09 09:42:16 +00008124RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8125 HandleScope scope(isolate);
8126 ASSERT(args.length() == 1);
8127 if (!V8::UseCrankshaft()) {
8128 return Smi::FromInt(4); // 4 == "never".
8129 }
8130 if (FLAG_always_opt) {
8131 return Smi::FromInt(3); // 3 == "always".
8132 }
8133 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8134 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8135 : Smi::FromInt(2); // 2 == "no".
8136}
8137
8138
8139RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8140 HandleScope scope(isolate);
8141 ASSERT(args.length() == 1);
8142 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8143 return Smi::FromInt(function->shared()->opt_count());
8144}
8145
8146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008147RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008148 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008149 ASSERT(args.length() == 1);
8150 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8151
8152 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008153 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154
8155 // We have hit a back edge in an unoptimized frame for a function that was
8156 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008157 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008158 // Keep track of whether we've succeeded in optimizing.
8159 bool succeeded = unoptimized->optimizable();
8160 if (succeeded) {
8161 // If we are trying to do OSR when there are already optimized
8162 // activations of the function, it means (a) the function is directly or
8163 // indirectly recursive and (b) an optimized invocation has been
8164 // deoptimized so that we are currently in an unoptimized activation.
8165 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008166 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008167 while (succeeded && !it.done()) {
8168 JavaScriptFrame* frame = it.frame();
8169 succeeded = !frame->is_optimized() || frame->function() != *function;
8170 it.Advance();
8171 }
8172 }
8173
8174 int ast_id = AstNode::kNoNumber;
8175 if (succeeded) {
8176 // The top JS function is this one, the PC is somewhere in the
8177 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008178 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 JavaScriptFrame* frame = it.frame();
8180 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008181 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008182 ASSERT(unoptimized->contains(frame->pc()));
8183
8184 // Use linear search of the unoptimized code's stack check table to find
8185 // the AST id matching the PC.
8186 Address start = unoptimized->instruction_start();
8187 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008188 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008189 uint32_t table_length = Memory::uint32_at(table_cursor);
8190 table_cursor += kIntSize;
8191 for (unsigned i = 0; i < table_length; ++i) {
8192 // Table entries are (AST id, pc offset) pairs.
8193 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8194 if (pc_offset == target_pc_offset) {
8195 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8196 break;
8197 }
8198 table_cursor += 2 * kIntSize;
8199 }
8200 ASSERT(ast_id != AstNode::kNoNumber);
8201 if (FLAG_trace_osr) {
8202 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8203 function->PrintName();
8204 PrintF("]\n");
8205 }
8206
8207 // Try to compile the optimized code. A true return value from
8208 // CompileOptimized means that compilation succeeded, not necessarily
8209 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008210 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8211 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008212 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8213 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008214 if (data->OsrPcOffset()->value() >= 0) {
8215 if (FLAG_trace_osr) {
8216 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008218 }
8219 ASSERT(data->OsrAstId()->value() == ast_id);
8220 } else {
8221 // We may never generate the desired OSR entry if we emit an
8222 // early deoptimize.
8223 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008224 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008225 } else {
8226 succeeded = false;
8227 }
8228 }
8229
8230 // Revert to the original stack checks in the original unoptimized code.
8231 if (FLAG_trace_osr) {
8232 PrintF("[restoring original stack checks in ");
8233 function->PrintName();
8234 PrintF("]\n");
8235 }
8236 StackCheckStub check_stub;
8237 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008238 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008239 Deoptimizer::RevertStackCheckCode(*unoptimized,
8240 *check_code,
8241 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008242
8243 // Allow OSR only at nesting level zero again.
8244 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8245
8246 // If the optimization attempt succeeded, return the AST id tagged as a
8247 // smi. This tells the builtin that we need to translate the unoptimized
8248 // frame to an optimized one.
8249 if (succeeded) {
8250 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8251 return Smi::FromInt(ast_id);
8252 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008253 if (function->IsMarkedForLazyRecompilation()) {
8254 function->ReplaceCode(function->shared()->code());
8255 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008256 return Smi::FromInt(-1);
8257 }
8258}
8259
8260
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008261RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8262 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8263 return isolate->heap()->undefined_value();
8264}
8265
8266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008267RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 ASSERT(args.length() == 1);
8270 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8271 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8272}
8273
8274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008275RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008277 ASSERT(args.length() == 1);
8278 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8279 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8280}
8281
8282
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008283RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008285 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286
kasper.lund7276f142008-07-30 08:49:36 +00008287 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008288 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008289 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 { MaybeObject* maybe_result =
8291 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008292 if (!maybe_result->ToObject(&result)) return maybe_result;
8293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296
kasper.lund7276f142008-07-30 08:49:36 +00008297 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298}
8299
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008301RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8302 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008303 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008304 JSObject* extension_object;
8305 if (args[0]->IsJSObject()) {
8306 extension_object = JSObject::cast(args[0]);
8307 } else {
8308 // Convert the object to a proper JavaScript object.
8309 MaybeObject* maybe_js_object = args[0]->ToObject();
8310 if (!maybe_js_object->To(&extension_object)) {
8311 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8312 HandleScope scope(isolate);
8313 Handle<Object> handle = args.at<Object>(0);
8314 Handle<Object> result =
8315 isolate->factory()->NewTypeError("with_expression",
8316 HandleVector(&handle, 1));
8317 return isolate->Throw(*result);
8318 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008319 return maybe_js_object;
8320 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 }
8322 }
8323
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008324 JSFunction* function;
8325 if (args[1]->IsSmi()) {
8326 // A smi sentinel indicates a context nested inside global code rather
8327 // than some function. There is a canonical empty function that can be
8328 // gotten from the global context.
8329 function = isolate->context()->global_context()->closure();
8330 } else {
8331 function = JSFunction::cast(args[1]);
8332 }
8333
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008334 Context* context;
8335 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008336 isolate->heap()->AllocateWithContext(function,
8337 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008338 extension_object);
8339 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008340 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008341 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008342}
8343
8344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008345RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008346 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008347 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008348 String* name = String::cast(args[0]);
8349 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008350 JSFunction* function;
8351 if (args[2]->IsSmi()) {
8352 // A smi sentinel indicates a context nested inside global code rather
8353 // than some function. There is a canonical empty function that can be
8354 // gotten from the global context.
8355 function = isolate->context()->global_context()->closure();
8356 } else {
8357 function = JSFunction::cast(args[2]);
8358 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008359 Context* context;
8360 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008361 isolate->heap()->AllocateCatchContext(function,
8362 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008363 name,
8364 thrown_object);
8365 if (!maybe_context->To(&context)) return maybe_context;
8366 isolate->set_context(context);
8367 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008368}
8369
8370
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008371RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8372 NoHandleAllocation ha;
8373 ASSERT(args.length() == 2);
8374 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8375 JSFunction* function;
8376 if (args[1]->IsSmi()) {
8377 // A smi sentinel indicates a context nested inside global code rather
8378 // than some function. There is a canonical empty function that can be
8379 // gotten from the global context.
8380 function = isolate->context()->global_context()->closure();
8381 } else {
8382 function = JSFunction::cast(args[1]);
8383 }
8384 Context* context;
8385 MaybeObject* maybe_context =
8386 isolate->heap()->AllocateBlockContext(function,
8387 isolate->context(),
8388 scope_info);
8389 if (!maybe_context->To(&context)) return maybe_context;
8390 isolate->set_context(context);
8391 return context;
8392}
8393
8394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008395RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008396 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 ASSERT(args.length() == 2);
8398
8399 CONVERT_ARG_CHECKED(Context, context, 0);
8400 CONVERT_ARG_CHECKED(String, name, 1);
8401
8402 int index;
8403 PropertyAttributes attributes;
8404 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008405 BindingFlags binding_flags;
8406 Handle<Object> holder = context->Lookup(name,
8407 flags,
8408 &index,
8409 &attributes,
8410 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008411
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008412 // If the slot was not found the result is true.
8413 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415 }
8416
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008417 // If the slot was found in a context, it should be DONT_DELETE.
8418 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008420 }
8421
8422 // The slot was found in a JSObject, either a context extension object,
8423 // the global object, or an arguments object. Try to delete it
8424 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8425 // which allows deleting all parameters in functions that mention
8426 // 'arguments', we do this even for the case of slots found on an
8427 // arguments object. The slot was found on an arguments object if the
8428 // index is non-negative.
8429 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8430 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008431 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008432 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008433 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435}
8436
8437
ager@chromium.orga1645e22009-09-09 19:27:10 +00008438// A mechanism to return a pair of Object pointers in registers (if possible).
8439// How this is achieved is calling convention-dependent.
8440// All currently supported x86 compiles uses calling conventions that are cdecl
8441// variants where a 64-bit value is returned in two 32-bit registers
8442// (edx:eax on ia32, r1:r0 on ARM).
8443// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8444// In Win64 calling convention, a struct of two pointers is returned in memory,
8445// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008446#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008447struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008448 MaybeObject* x;
8449 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008450};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008451
lrn@chromium.org303ada72010-10-27 09:33:13 +00008452static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008453 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008454 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8455 // In Win64 they are assigned to a hidden first argument.
8456 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008457}
8458#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008459typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008460static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008461 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008462 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008463}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008464#endif
8465
8466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008467static inline MaybeObject* Unhole(Heap* heap,
8468 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008469 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008470 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8471 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008472 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008473}
8474
8475
danno@chromium.org40cb8782011-05-25 07:58:50 +00008476static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8477 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008478 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008479 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008480 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008481 JSFunction* context_extension_function =
8482 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008483 // If the holder isn't a context extension object, we just return it
8484 // as the receiver. This allows arguments objects to be used as
8485 // receivers, but only if they are put in the context scope chain
8486 // explicitly via a with-statement.
8487 Object* constructor = holder->map()->constructor();
8488 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008489 // Fall back to using the global object as the implicit receiver if
8490 // the property turns out to be a local variable allocated in a
8491 // context extension object - introduced via eval. Implicit global
8492 // receivers are indicated with the hole value.
8493 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008494}
8495
8496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497static ObjectPair LoadContextSlotHelper(Arguments args,
8498 Isolate* isolate,
8499 bool throw_error) {
8500 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008501 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008502
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008503 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008504 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008505 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008506 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008507 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508
8509 int index;
8510 PropertyAttributes attributes;
8511 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008512 BindingFlags binding_flags;
8513 Handle<Object> holder = context->Lookup(name,
8514 flags,
8515 &index,
8516 &attributes,
8517 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008518
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008519 // If the index is non-negative, the slot has been found in a local
8520 // variable or a parameter. Read it from the context object or the
8521 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008522 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008523 // If the "property" we were looking for is a local variable or an
8524 // argument in a context, the receiver is the global object; see
8525 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008526 //
8527 // Use the hole as the receiver to signal that the receiver is
8528 // implicit and that the global receiver should be used.
8529 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008530 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008531 ? Context::cast(*holder)->get(index)
8532 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008533 // Check for uninitialized bindings.
8534 if (holder->IsContext() &&
8535 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8536 value->IsTheHole()) {
8537 Handle<Object> reference_error =
8538 isolate->factory()->NewReferenceError("not_defined",
8539 HandleVector(&name, 1));
8540 return MakePair(isolate->Throw(*reference_error), NULL);
8541 } else {
8542 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8543 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 }
8545
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008546 // If the holder is found, we read the property from it.
8547 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008548 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008549 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008550 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008551 if (object->IsGlobalObject()) {
8552 receiver = GlobalObject::cast(object)->global_receiver();
8553 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008554 // Use the hole as the receiver to signal that the receiver is
8555 // implicit and that the global receiver should be used.
8556 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008557 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008558 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008559 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008560
8561 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008562 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008563
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008564 // No need to unhole the value here. This is taken care of by the
8565 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008566 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008567 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568 }
8569
8570 if (throw_error) {
8571 // The property doesn't exist - throw exception.
8572 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 isolate->factory()->NewReferenceError("not_defined",
8574 HandleVector(&name, 1));
8575 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008577 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 return MakePair(isolate->heap()->undefined_value(),
8579 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008580 }
8581}
8582
8583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008584RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008585 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008586}
8587
8588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008589RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008591}
8592
8593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008594RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008595 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008596 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008598 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008600 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008601 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008602 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8603 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008604 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008605
8606 int index;
8607 PropertyAttributes attributes;
8608 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008609 BindingFlags binding_flags;
8610 Handle<Object> holder = context->Lookup(name,
8611 flags,
8612 &index,
8613 &attributes,
8614 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615
8616 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008617 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008618 Handle<Context> context = Handle<Context>::cast(holder);
8619 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8620 context->get(index)->IsTheHole()) {
8621 Handle<Object> error =
8622 isolate->factory()->NewReferenceError("not_defined",
8623 HandleVector(&name, 1));
8624 return isolate->Throw(*error);
8625 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626 // Ignore if read_only variable.
8627 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008628 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008629 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008630 } else if (strict_mode == kStrictMode) {
8631 // Setting read only property in strict mode.
8632 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008633 isolate->factory()->NewTypeError("strict_cannot_assign",
8634 HandleVector(&name, 1));
8635 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636 }
8637 } else {
8638 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008639 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008640 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008641 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008642 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008643 return Failure::Exception();
8644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008645 }
8646 return *value;
8647 }
8648
8649 // Slow case: The property is not in a FixedArray context.
8650 // It is either in an JSObject extension context or it was not found.
8651 Handle<JSObject> context_ext;
8652
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008653 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008654 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008655 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008657 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008658 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008659
8660 if (strict_mode == kStrictMode) {
8661 // Throw in strict mode (assignment to undefined variable).
8662 Handle<Object> error =
8663 isolate->factory()->NewReferenceError(
8664 "not_defined", HandleVector(&name, 1));
8665 return isolate->Throw(*error);
8666 }
8667 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008669 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670 }
8671
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008672 // Set the property, but ignore if read_only variable on the context
8673 // extension object itself.
8674 if ((attributes & READ_ONLY) == 0 ||
8675 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008676 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008677 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008678 SetProperty(context_ext, name, value, NONE, strict_mode));
8679 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008680 // Setting read only property in strict mode.
8681 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008682 isolate->factory()->NewTypeError(
8683 "strict_cannot_assign", HandleVector(&name, 1));
8684 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685 }
8686 return *value;
8687}
8688
8689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008690RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008691 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008692 ASSERT(args.length() == 1);
8693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008694 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695}
8696
8697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008698RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700 ASSERT(args.length() == 1);
8701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703}
8704
8705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008706RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008707 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008708 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008709}
8710
8711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008712RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 ASSERT(args.length() == 1);
8715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008718 isolate->factory()->NewReferenceError("not_defined",
8719 HandleVector(&name, 1));
8720 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721}
8722
8723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008724RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008725 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008726
8727 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 if (isolate->stack_guard()->IsStackOverflow()) {
8729 NoHandleAllocation na;
8730 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008733 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008734}
8735
8736
8737// NOTE: These PrintXXX functions are defined for all builds (not just
8738// DEBUG builds) because we may want to be able to trace function
8739// calls in all modes.
8740static void PrintString(String* str) {
8741 // not uncommon to have empty strings
8742 if (str->length() > 0) {
8743 SmartPointer<char> s =
8744 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8745 PrintF("%s", *s);
8746 }
8747}
8748
8749
8750static void PrintObject(Object* obj) {
8751 if (obj->IsSmi()) {
8752 PrintF("%d", Smi::cast(obj)->value());
8753 } else if (obj->IsString() || obj->IsSymbol()) {
8754 PrintString(String::cast(obj));
8755 } else if (obj->IsNumber()) {
8756 PrintF("%g", obj->Number());
8757 } else if (obj->IsFailure()) {
8758 PrintF("<failure>");
8759 } else if (obj->IsUndefined()) {
8760 PrintF("<undefined>");
8761 } else if (obj->IsNull()) {
8762 PrintF("<null>");
8763 } else if (obj->IsTrue()) {
8764 PrintF("<true>");
8765 } else if (obj->IsFalse()) {
8766 PrintF("<false>");
8767 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008768 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769 }
8770}
8771
8772
8773static int StackSize() {
8774 int n = 0;
8775 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8776 return n;
8777}
8778
8779
8780static void PrintTransition(Object* result) {
8781 // indentation
8782 { const int nmax = 80;
8783 int n = StackSize();
8784 if (n <= nmax)
8785 PrintF("%4d:%*s", n, n, "");
8786 else
8787 PrintF("%4d:%*s", n, nmax, "...");
8788 }
8789
8790 if (result == NULL) {
8791 // constructor calls
8792 JavaScriptFrameIterator it;
8793 JavaScriptFrame* frame = it.frame();
8794 if (frame->IsConstructor()) PrintF("new ");
8795 // function name
8796 Object* fun = frame->function();
8797 if (fun->IsJSFunction()) {
8798 PrintObject(JSFunction::cast(fun)->shared()->name());
8799 } else {
8800 PrintObject(fun);
8801 }
8802 // function arguments
8803 // (we are intentionally only printing the actually
8804 // supplied parameters, not all parameters required)
8805 PrintF("(this=");
8806 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008807 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808 for (int i = 0; i < length; i++) {
8809 PrintF(", ");
8810 PrintObject(frame->GetParameter(i));
8811 }
8812 PrintF(") {\n");
8813
8814 } else {
8815 // function result
8816 PrintF("} -> ");
8817 PrintObject(result);
8818 PrintF("\n");
8819 }
8820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008824 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 NoHandleAllocation ha;
8826 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828}
8829
8830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 NoHandleAllocation ha;
8833 PrintTransition(args[0]);
8834 return args[0]; // return TOS
8835}
8836
8837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008838RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008839 NoHandleAllocation ha;
8840 ASSERT(args.length() == 1);
8841
8842#ifdef DEBUG
8843 if (args[0]->IsString()) {
8844 // If we have a string, assume it's a code "marker"
8845 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008846 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008848 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8849 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008850 } else {
8851 PrintF("DebugPrint: ");
8852 }
8853 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008854 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008855 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008856 HeapObject::cast(args[0])->map()->Print();
8857 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008859 // ShortPrint is available in release mode. Print is not.
8860 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861#endif
8862 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008863 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864
8865 return args[0]; // return TOS
8866}
8867
8868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008869RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008870 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 isolate->PrintStack();
8873 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008874}
8875
8876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008877RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008879 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880
8881 // According to ECMA-262, section 15.9.1, page 117, the precision of
8882 // the number in a Date object representing a particular instant in
8883 // time is milliseconds. Therefore, we floor the result of getting
8884 // the OS time.
8885 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887}
8888
8889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008891 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008892 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008893
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008894 CONVERT_ARG_CHECKED(String, str, 0);
8895 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008897 CONVERT_ARG_CHECKED(JSArray, output, 1);
8898 RUNTIME_ASSERT(output->HasFastElements());
8899
8900 AssertNoAllocation no_allocation;
8901
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008902 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008903 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8904 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008905 String::FlatContent str_content = str->GetFlatContent();
8906 if (str_content.IsAscii()) {
8907 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008908 output_array,
8909 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008911 ASSERT(str_content.IsTwoByte());
8912 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008913 output_array,
8914 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008915 }
8916
8917 if (result) {
8918 return *output;
8919 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921 }
8922}
8923
8924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008925RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926 NoHandleAllocation ha;
8927 ASSERT(args.length() == 1);
8928
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008929 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008930 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932}
8933
8934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008935RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008936 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008937 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940}
8941
8942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008943RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 NoHandleAllocation ha;
8945 ASSERT(args.length() == 1);
8946
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008947 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008948 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008949}
8950
8951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008952RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008953 ASSERT(args.length() == 1);
8954 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008955 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008956 return JSGlobalObject::cast(global)->global_receiver();
8957}
8958
8959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008960RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008961 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008962 ASSERT_EQ(1, args.length());
8963 CONVERT_ARG_CHECKED(String, source, 0);
8964
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008965 source = Handle<String>(source->TryFlattenGetString());
8966 // Optimized fast case where we only have ascii characters.
8967 Handle<Object> result;
8968 if (source->IsSeqAsciiString()) {
8969 result = JsonParser<true>::Parse(source);
8970 } else {
8971 result = JsonParser<false>::Parse(source);
8972 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008973 if (result.is_null()) {
8974 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008975 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008976 return Failure::Exception();
8977 }
8978 return *result;
8979}
8980
8981
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008982bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8983 Handle<Context> context) {
8984 if (context->allow_code_gen_from_strings()->IsFalse()) {
8985 // Check with callback if set.
8986 AllowCodeGenerationFromStringsCallback callback =
8987 isolate->allow_code_gen_callback();
8988 if (callback == NULL) {
8989 // No callback set and code generation disallowed.
8990 return false;
8991 } else {
8992 // Callback set. Let it decide if code generation is allowed.
8993 VMState state(isolate, EXTERNAL);
8994 return callback(v8::Utils::ToLocal(context));
8995 }
8996 }
8997 return true;
8998}
8999
9000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009001RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009002 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009003 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009004 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009005
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009006 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009007 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009008
9009 // Check if global context allows code generation from
9010 // strings. Throw an exception if it doesn't.
9011 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9012 return isolate->Throw(*isolate->factory()->NewError(
9013 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9014 }
9015
9016 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009017 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9018 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009019 true,
9020 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009021 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009022 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9024 context,
9025 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026 return *fun;
9027}
9028
9029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009030static ObjectPair CompileGlobalEval(Isolate* isolate,
9031 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009032 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009033 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009034 Handle<Context> context = Handle<Context>(isolate->context());
9035 Handle<Context> global_context = Handle<Context>(context->global_context());
9036
9037 // Check if global context allows code generation from
9038 // strings. Throw an exception if it doesn't.
9039 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9040 isolate->Throw(*isolate->factory()->NewError(
9041 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9042 return MakePair(Failure::Exception(), NULL);
9043 }
9044
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009045 // Deal with a normal eval call with a string argument. Compile it
9046 // and return the compiled function bound in the local context.
9047 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9048 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009049 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009050 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009051 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009052 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 Handle<JSFunction> compiled =
9054 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009055 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009056 return MakePair(*compiled, *receiver);
9057}
9058
9059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009060RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009061 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009064 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009065 Handle<Object> receiver; // Will be overwritten.
9066
9067 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009069#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009070 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009071 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009072 StackFrameLocator locator;
9073 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009074 ASSERT(Context::cast(frame->context()) == *context);
9075#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009076
9077 // Find where the 'eval' symbol is bound. It is unaliased only if
9078 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009079 int index = -1;
9080 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009081 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009082 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009083 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9084 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009085 &index,
9086 &attributes,
9087 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009088 // Stop search when eval is found or when the global context is
9089 // reached.
9090 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009091 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009092 }
9093
iposva@chromium.org245aa852009-02-10 00:49:54 +00009094 // If eval could not be resolved, it has been deleted and we need to
9095 // throw a reference error.
9096 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009098 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 isolate->factory()->NewReferenceError("not_defined",
9100 HandleVector(&name, 1));
9101 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009102 }
9103
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009104 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009105 // 'eval' is not bound in the global context. Just call the function
9106 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009107 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009108 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009109 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009110 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009111 }
9112
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009113 // 'eval' is bound in the global context, but it may have been overwritten.
9114 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009115 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009116 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009117 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009118 }
9119
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009120 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009121 return CompileGlobalEval(isolate,
9122 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009123 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009124 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009125}
9126
9127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009128RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009129 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009132 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009133
9134 // 'eval' is bound in the global context, but it may have been overwritten.
9135 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009137 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009138 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009139 }
9140
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009141 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 return CompileGlobalEval(isolate,
9143 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009144 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009145 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009146}
9147
9148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 // This utility adjusts the property attributes for newly created Function
9151 // object ("new Function(...)") by changing the map.
9152 // All it does is changing the prototype property to enumerable
9153 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 ASSERT(args.length() == 1);
9156 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157
9158 Handle<Map> map = func->shared()->strict_mode()
9159 ? isolate->strict_mode_function_instance_map()
9160 : isolate->function_instance_map();
9161
9162 ASSERT(func->map()->instance_type() == map->instance_type());
9163 ASSERT(func->map()->instance_size() == map->instance_size());
9164 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 return *func;
9166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009170 // Allocate a block of memory in NewSpace (filled with a filler).
9171 // Use as fallback for allocation in generated code when NewSpace
9172 // is full.
9173 ASSERT(args.length() == 1);
9174 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9175 int size = size_smi->value();
9176 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9177 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 Heap* heap = isolate->heap();
9179 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009180 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009181 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009183 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009185 }
9186 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009187 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009188}
9189
9190
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009191// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009192// array. Returns true if the element was pushed on the stack and
9193// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009194RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009195 ASSERT(args.length() == 2);
9196 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009197 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009198 RUNTIME_ASSERT(array->HasFastElements());
9199 int length = Smi::cast(array->length())->value();
9200 FixedArray* elements = FixedArray::cast(array->elements());
9201 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009202 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009203 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009204 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009205 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009206 { MaybeObject* maybe_obj =
9207 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009208 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009211}
9212
9213
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009214/**
9215 * A simple visitor visits every element of Array's.
9216 * The backend storage can be a fixed array for fast elements case,
9217 * or a dictionary for sparse array. Since Dictionary is a subtype
9218 * of FixedArray, the class can be used by both fast and slow cases.
9219 * The second parameter of the constructor, fast_elements, specifies
9220 * whether the storage is a FixedArray or Dictionary.
9221 *
9222 * An index limit is used to deal with the situation that a result array
9223 * length overflows 32-bit non-negative integer.
9224 */
9225class ArrayConcatVisitor {
9226 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 ArrayConcatVisitor(Isolate* isolate,
9228 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009229 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 isolate_(isolate),
9231 storage_(Handle<FixedArray>::cast(
9232 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009233 index_offset_(0u),
9234 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009235
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009236 ~ArrayConcatVisitor() {
9237 clear_storage();
9238 }
9239
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009240 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009241 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009242 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009243
9244 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009245 if (index < static_cast<uint32_t>(storage_->length())) {
9246 storage_->set(index, *elm);
9247 return;
9248 }
9249 // Our initial estimate of length was foiled, possibly by
9250 // getters on the arrays increasing the length of later arrays
9251 // during iteration.
9252 // This shouldn't happen in anything but pathological cases.
9253 SetDictionaryMode(index);
9254 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009255 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009256 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009257 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009258 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009260 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009261 // Dictionary needed to grow.
9262 clear_storage();
9263 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009264 }
9265}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009266
9267 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009268 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9269 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009270 } else {
9271 index_offset_ += delta;
9272 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009273 }
9274
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009275 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009277 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009278 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 Handle<Map> map;
9280 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009281 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009282 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009284 }
9285 array->set_map(*map);
9286 array->set_length(*length);
9287 array->set_elements(*storage_);
9288 return array;
9289 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009290
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009291 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009292 // Convert storage to dictionary mode.
9293 void SetDictionaryMode(uint32_t index) {
9294 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009295 Handle<FixedArray> current_storage(*storage_);
9296 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009298 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9299 for (uint32_t i = 0; i < current_length; i++) {
9300 HandleScope loop_scope;
9301 Handle<Object> element(current_storage->get(i));
9302 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009303 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009304 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009305 if (!new_storage.is_identical_to(slow_storage)) {
9306 slow_storage = loop_scope.CloseAndEscape(new_storage);
9307 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009308 }
9309 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009310 clear_storage();
9311 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009312 fast_elements_ = false;
9313 }
9314
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009315 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 isolate_->global_handles()->Destroy(
9317 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009318 }
9319
9320 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009321 storage_ = Handle<FixedArray>::cast(
9322 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009323 }
9324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009326 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009327 // Index after last seen index. Always less than or equal to
9328 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009329 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009330 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009331};
9332
9333
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334static uint32_t EstimateElementCount(Handle<JSArray> array) {
9335 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9336 int element_count = 0;
9337 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009338 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009339 // Fast elements can't have lengths that are not representable by
9340 // a 32-bit signed integer.
9341 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9342 int fast_length = static_cast<int>(length);
9343 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9344 for (int i = 0; i < fast_length; i++) {
9345 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009346 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009347 break;
9348 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009349 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 Handle<NumberDictionary> dictionary(
9351 NumberDictionary::cast(array->elements()));
9352 int capacity = dictionary->Capacity();
9353 for (int i = 0; i < capacity; i++) {
9354 Handle<Object> key(dictionary->KeyAt(i));
9355 if (dictionary->IsKey(*key)) {
9356 element_count++;
9357 }
9358 }
9359 break;
9360 }
9361 default:
9362 // External arrays are always dense.
9363 return length;
9364 }
9365 // As an estimate, we assume that the prototype doesn't contain any
9366 // inherited elements.
9367 return element_count;
9368}
9369
9370
9371
9372template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009373static void IterateExternalArrayElements(Isolate* isolate,
9374 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009375 bool elements_are_ints,
9376 bool elements_are_guaranteed_smis,
9377 ArrayConcatVisitor* visitor) {
9378 Handle<ExternalArrayClass> array(
9379 ExternalArrayClass::cast(receiver->elements()));
9380 uint32_t len = static_cast<uint32_t>(array->length());
9381
9382 ASSERT(visitor != NULL);
9383 if (elements_are_ints) {
9384 if (elements_are_guaranteed_smis) {
9385 for (uint32_t j = 0; j < len; j++) {
9386 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009387 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009388 visitor->visit(j, e);
9389 }
9390 } else {
9391 for (uint32_t j = 0; j < len; j++) {
9392 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009393 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009394 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9395 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9396 visitor->visit(j, e);
9397 } else {
9398 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009399 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009400 visitor->visit(j, e);
9401 }
9402 }
9403 }
9404 } else {
9405 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009407 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 visitor->visit(j, e);
9409 }
9410 }
9411}
9412
9413
9414// Used for sorting indices in a List<uint32_t>.
9415static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9416 uint32_t a = *ap;
9417 uint32_t b = *bp;
9418 return (a == b) ? 0 : (a < b) ? -1 : 1;
9419}
9420
9421
9422static void CollectElementIndices(Handle<JSObject> object,
9423 uint32_t range,
9424 List<uint32_t>* indices) {
9425 JSObject::ElementsKind kind = object->GetElementsKind();
9426 switch (kind) {
9427 case JSObject::FAST_ELEMENTS: {
9428 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9429 uint32_t length = static_cast<uint32_t>(elements->length());
9430 if (range < length) length = range;
9431 for (uint32_t i = 0; i < length; i++) {
9432 if (!elements->get(i)->IsTheHole()) {
9433 indices->Add(i);
9434 }
9435 }
9436 break;
9437 }
9438 case JSObject::DICTIONARY_ELEMENTS: {
9439 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009440 uint32_t capacity = dict->Capacity();
9441 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009442 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009443 Handle<Object> k(dict->KeyAt(j));
9444 if (dict->IsKey(*k)) {
9445 ASSERT(k->IsNumber());
9446 uint32_t index = static_cast<uint32_t>(k->Number());
9447 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009449 }
9450 }
9451 }
9452 break;
9453 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009454 default: {
9455 int dense_elements_length;
9456 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009457 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009458 dense_elements_length =
9459 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009460 break;
9461 }
9462 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009463 dense_elements_length =
9464 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009465 break;
9466 }
9467 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009468 dense_elements_length =
9469 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009470 break;
9471 }
9472 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009473 dense_elements_length =
9474 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009475 break;
9476 }
9477 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009478 dense_elements_length =
9479 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009480 break;
9481 }
9482 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009483 dense_elements_length =
9484 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009485 break;
9486 }
9487 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009488 dense_elements_length =
9489 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009490 break;
9491 }
9492 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009493 dense_elements_length =
9494 ExternalFloatArray::cast(object->elements())->length();
9495 break;
9496 }
9497 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9498 dense_elements_length =
9499 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009500 break;
9501 }
9502 default:
9503 UNREACHABLE();
9504 dense_elements_length = 0;
9505 break;
9506 }
9507 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9508 if (range <= length) {
9509 length = range;
9510 // We will add all indices, so we might as well clear it first
9511 // and avoid duplicates.
9512 indices->Clear();
9513 }
9514 for (uint32_t i = 0; i < length; i++) {
9515 indices->Add(i);
9516 }
9517 if (length == range) return; // All indices accounted for already.
9518 break;
9519 }
9520 }
9521
9522 Handle<Object> prototype(object->GetPrototype());
9523 if (prototype->IsJSObject()) {
9524 // The prototype will usually have no inherited element indices,
9525 // but we have to check.
9526 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9527 }
9528}
9529
9530
9531/**
9532 * A helper function that visits elements of a JSArray in numerical
9533 * order.
9534 *
9535 * The visitor argument called for each existing element in the array
9536 * with the element index and the element's value.
9537 * Afterwards it increments the base-index of the visitor by the array
9538 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009539 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541static bool IterateElements(Isolate* isolate,
9542 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009543 ArrayConcatVisitor* visitor) {
9544 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9545 switch (receiver->GetElementsKind()) {
9546 case JSObject::FAST_ELEMENTS: {
9547 // Run through the elements FixedArray and use HasElement and GetElement
9548 // to check the prototype for missing elements.
9549 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9550 int fast_length = static_cast<int>(length);
9551 ASSERT(fast_length <= elements->length());
9552 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 HandleScope loop_scope(isolate);
9554 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009555 if (!element_value->IsTheHole()) {
9556 visitor->visit(j, element_value);
9557 } else if (receiver->HasElement(j)) {
9558 // Call GetElement on receiver, not its prototype, or getters won't
9559 // have the correct receiver.
9560 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009561 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009562 visitor->visit(j, element_value);
9563 }
9564 }
9565 break;
9566 }
9567 case JSObject::DICTIONARY_ELEMENTS: {
9568 Handle<NumberDictionary> dict(receiver->element_dictionary());
9569 List<uint32_t> indices(dict->Capacity() / 2);
9570 // Collect all indices in the object and the prototypes less
9571 // than length. This might introduce duplicates in the indices list.
9572 CollectElementIndices(receiver, length, &indices);
9573 indices.Sort(&compareUInt32);
9574 int j = 0;
9575 int n = indices.length();
9576 while (j < n) {
9577 HandleScope loop_scope;
9578 uint32_t index = indices[j];
9579 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009580 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009581 visitor->visit(index, element);
9582 // Skip to next different index (i.e., omit duplicates).
9583 do {
9584 j++;
9585 } while (j < n && indices[j] == index);
9586 }
9587 break;
9588 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009589 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9590 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9591 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009592 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009593 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009594 visitor->visit(j, e);
9595 }
9596 break;
9597 }
9598 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9599 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009600 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 break;
9602 }
9603 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9604 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009605 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009606 break;
9607 }
9608 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9609 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009611 break;
9612 }
9613 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9614 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009615 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 break;
9617 }
9618 case JSObject::EXTERNAL_INT_ELEMENTS: {
9619 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009621 break;
9622 }
9623 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9624 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 break;
9627 }
9628 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9629 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009630 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009631 break;
9632 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009633 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9634 IterateExternalArrayElements<ExternalDoubleArray, double>(
9635 isolate, receiver, false, false, visitor);
9636 break;
9637 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009638 default:
9639 UNREACHABLE();
9640 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009641 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009642 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009643 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009644}
9645
9646
9647/**
9648 * Array::concat implementation.
9649 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009650 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009651 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009652 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009653RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009654 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009655 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009656
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9658 int argument_count = static_cast<int>(arguments->length()->Number());
9659 RUNTIME_ASSERT(arguments->HasFastElements());
9660 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009661
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 // Pass 1: estimate the length and number of elements of the result.
9663 // The actual length can be larger if any of the arguments have getters
9664 // that mutate other arguments (but will otherwise be precise).
9665 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667 uint32_t estimate_result_length = 0;
9668 uint32_t estimate_nof_elements = 0;
9669 {
9670 for (int i = 0; i < argument_count; i++) {
9671 HandleScope loop_scope;
9672 Handle<Object> obj(elements->get(i));
9673 uint32_t length_estimate;
9674 uint32_t element_estimate;
9675 if (obj->IsJSArray()) {
9676 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9677 length_estimate =
9678 static_cast<uint32_t>(array->length()->Number());
9679 element_estimate =
9680 EstimateElementCount(array);
9681 } else {
9682 length_estimate = 1;
9683 element_estimate = 1;
9684 }
9685 // Avoid overflows by capping at kMaxElementCount.
9686 if (JSObject::kMaxElementCount - estimate_result_length <
9687 length_estimate) {
9688 estimate_result_length = JSObject::kMaxElementCount;
9689 } else {
9690 estimate_result_length += length_estimate;
9691 }
9692 if (JSObject::kMaxElementCount - estimate_nof_elements <
9693 element_estimate) {
9694 estimate_nof_elements = JSObject::kMaxElementCount;
9695 } else {
9696 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009697 }
9698 }
9699 }
9700
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009701 // If estimated number of elements is more than half of length, a
9702 // fixed array (fast case) is more time and space-efficient than a
9703 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009705
9706 Handle<FixedArray> storage;
9707 if (fast_case) {
9708 // The backing storage array must have non-existing elements to
9709 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 storage = isolate->factory()->NewFixedArrayWithHoles(
9711 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009712 } else {
9713 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9714 uint32_t at_least_space_for = estimate_nof_elements +
9715 (estimate_nof_elements >> 2);
9716 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009717 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009718 }
9719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009721
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009722 for (int i = 0; i < argument_count; i++) {
9723 Handle<Object> obj(elements->get(i));
9724 if (obj->IsJSArray()) {
9725 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009726 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009727 return Failure::Exception();
9728 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 } else {
9730 visitor.visit(0, obj);
9731 visitor.increase_index_offset(1);
9732 }
9733 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009734
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009736}
9737
9738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739// This will not allocate (flatten the string), but it may run
9740// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009741RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009742 NoHandleAllocation ha;
9743 ASSERT(args.length() == 1);
9744
9745 CONVERT_CHECKED(String, string, args[0]);
9746 StringInputBuffer buffer(string);
9747 while (buffer.has_more()) {
9748 uint16_t character = buffer.GetNext();
9749 PrintF("%c", character);
9750 }
9751 return string;
9752}
9753
ager@chromium.org5ec48922009-05-05 07:25:34 +00009754// Moves all own elements of an object, that are below a limit, to positions
9755// starting at zero. All undefined values are placed after non-undefined values,
9756// and are followed by non-existing element. Does not change the length
9757// property.
9758// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009759RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009760 ASSERT(args.length() == 2);
9761 CONVERT_CHECKED(JSObject, object, args[0]);
9762 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9763 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764}
9765
9766
9767// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009768RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769 ASSERT(args.length() == 2);
9770 CONVERT_CHECKED(JSArray, from, args[0]);
9771 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009772 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009773 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009774 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9775 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009776 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009777 } else if (new_elements->map() ==
9778 isolate->heap()->fixed_double_array_map()) {
9779 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009780 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009781 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009782 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009783 Object* new_map;
9784 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009785 to->set_map(Map::cast(new_map));
9786 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009787 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009788 Object* obj;
9789 { MaybeObject* maybe_obj = from->ResetElements();
9790 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9791 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009792 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793 return to;
9794}
9795
9796
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009797// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009798RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009800 CONVERT_CHECKED(JSObject, object, args[0]);
9801 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009803 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009804 } else if (object->IsJSArray()) {
9805 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009807 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 }
9809}
9810
9811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009812RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009813 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009814
9815 ASSERT_EQ(3, args.length());
9816
ager@chromium.orgac091b72010-05-05 07:34:42 +00009817 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009818 Handle<Object> key1 = args.at<Object>(1);
9819 Handle<Object> key2 = args.at<Object>(2);
9820
9821 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009822 if (!key1->ToArrayIndex(&index1)
9823 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009825 }
9826
ager@chromium.orgac091b72010-05-05 07:34:42 +00009827 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9828 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009830 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009832
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 RETURN_IF_EMPTY_HANDLE(isolate,
9834 SetElement(jsobject, index1, tmp2, kStrictMode));
9835 RETURN_IF_EMPTY_HANDLE(isolate,
9836 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009838 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009839}
9840
9841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009843// might have elements. Can either return keys (positive integers) or
9844// intervals (pair of a negative integer (-start-1) followed by a
9845// positive (length)) or undefined values.
9846// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009847RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009848 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009850 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009851 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009852 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 // Create an array and get all the keys into it, then remove all the
9854 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009855 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 int keys_length = keys->length();
9857 for (int i = 0; i < keys_length; i++) {
9858 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009859 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009860 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861 // Zap invalid keys.
9862 keys->set_undefined(i);
9863 }
9864 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009867 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009868 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009870 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009871 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009872 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009873 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009874 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009879 }
9880}
9881
9882
9883// DefineAccessor takes an optional final argument which is the
9884// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9885// to the way accessors are implemented, it is set for both the getter
9886// and setter on the first call to DefineAccessor and ignored on
9887// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009888RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009889 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9890 // Compute attributes.
9891 PropertyAttributes attributes = NONE;
9892 if (args.length() == 5) {
9893 CONVERT_CHECKED(Smi, attrs, args[4]);
9894 int value = attrs->value();
9895 // Only attribute bits should be set.
9896 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9897 attributes = static_cast<PropertyAttributes>(value);
9898 }
9899
9900 CONVERT_CHECKED(JSObject, obj, args[0]);
9901 CONVERT_CHECKED(String, name, args[1]);
9902 CONVERT_CHECKED(Smi, flag, args[2]);
9903 CONVERT_CHECKED(JSFunction, fun, args[3]);
9904 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9905}
9906
9907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009908RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909 ASSERT(args.length() == 3);
9910 CONVERT_CHECKED(JSObject, obj, args[0]);
9911 CONVERT_CHECKED(String, name, args[1]);
9912 CONVERT_CHECKED(Smi, flag, args[2]);
9913 return obj->LookupAccessor(name, flag->value() == 0);
9914}
9915
9916
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009917#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009918RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009919 ASSERT(args.length() == 0);
9920 return Execution::DebugBreakHelper();
9921}
9922
9923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924// Helper functions for wrapping and unwrapping stack frame ids.
9925static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009926 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009927 return Smi::FromInt(id >> 2);
9928}
9929
9930
9931static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9932 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9933}
9934
9935
9936// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009937// args[0]: debug event listener function to set or null or undefined for
9938// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009940RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009942 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9943 args[0]->IsUndefined() ||
9944 args[0]->IsNull());
9945 Handle<Object> callback = args.at<Object>(0);
9946 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950}
9951
9952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009953RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009954 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 isolate->stack_guard()->DebugBreak();
9956 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957}
9958
9959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960static MaybeObject* DebugLookupResultValue(Heap* heap,
9961 Object* receiver,
9962 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009963 LookupResult* result,
9964 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009965 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009967 case NORMAL:
9968 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009969 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 }
9972 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009973 case FIELD:
9974 value =
9975 JSObject::cast(
9976 result->holder())->FastPropertyAt(result->GetFieldIndex());
9977 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009979 }
9980 return value;
9981 case CONSTANT_FUNCTION:
9982 return result->GetConstantFunction();
9983 case CALLBACKS: {
9984 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009985 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009986 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009987 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009988 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009989 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009990 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 maybe_value = heap->isolate()->pending_exception();
9992 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009993 if (caught_exception != NULL) {
9994 *caught_exception = true;
9995 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009996 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009997 }
9998 return value;
9999 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010001 }
10002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010004 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010005 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010006 case CONSTANT_TRANSITION:
10007 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 default:
10010 UNREACHABLE();
10011 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010012 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014}
10015
10016
ager@chromium.org32912102009-01-16 10:38:43 +000010017// Get debugger related details for an object property.
10018// args[0]: object holding property
10019// args[1]: name of the property
10020//
10021// The array returned contains the following information:
10022// 0: Property value
10023// 1: Property details
10024// 2: Property value is exception
10025// 3: Getter function if defined
10026// 4: Setter function if defined
10027// Items 2-4 are only filled if the property has either a getter or a setter
10028// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010029RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010030 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031
10032 ASSERT(args.length() == 2);
10033
10034 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10035 CONVERT_ARG_CHECKED(String, name, 1);
10036
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010037 // Make sure to set the current context to the context before the debugger was
10038 // entered (if the debugger is entered). The reason for switching context here
10039 // is that for some property lookups (accessors and interceptors) callbacks
10040 // into the embedding application can occour, and the embedding application
10041 // could have the assumption that its own global context is the current
10042 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 SaveContext save(isolate);
10044 if (isolate->debug()->InDebugger()) {
10045 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010046 }
10047
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010048 // Skip the global proxy as it has no properties and always delegates to the
10049 // real global object.
10050 if (obj->IsJSGlobalProxy()) {
10051 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10052 }
10053
10054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055 // Check if the name is trivially convertible to an index and get the element
10056 // if so.
10057 uint32_t index;
10058 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010060 Object* element_or_char;
10061 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010063 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10064 return maybe_element_or_char;
10065 }
10066 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010067 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010069 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070 }
10071
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010072 // Find the number of objects making up this.
10073 int length = LocalPrototypeChainLength(*obj);
10074
10075 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010076 Handle<JSObject> jsproto = obj;
10077 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010078 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010079 jsproto->LocalLookup(*name, &result);
10080 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010081 // LookupResult is not GC safe as it holds raw object pointers.
10082 // GC can happen later in this code so put the required fields into
10083 // local variables using handles when required for later use.
10084 PropertyType result_type = result.type();
10085 Handle<Object> result_callback_obj;
10086 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10088 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010089 }
10090 Smi* property_details = result.GetPropertyDetails().AsSmi();
10091 // DebugLookupResultValue can cause GC so details from LookupResult needs
10092 // to be copied to handles before this.
10093 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010094 Object* raw_value;
10095 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010096 DebugLookupResultValue(isolate->heap(), *obj, *name,
10097 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010098 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10099 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010100 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010101
10102 // If the callback object is a fixed array then it contains JavaScript
10103 // getter and/or setter.
10104 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10105 result_callback_obj->IsFixedArray();
10106 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010108 details->set(0, *value);
10109 details->set(1, property_details);
10110 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010111 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010112 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10113 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10114 }
10115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010117 }
10118 if (i < length - 1) {
10119 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10120 }
10121 }
10122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010123 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124}
10125
10126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010127RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129
10130 ASSERT(args.length() == 2);
10131
10132 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10133 CONVERT_ARG_CHECKED(String, name, 1);
10134
10135 LookupResult result;
10136 obj->Lookup(*name, &result);
10137 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010138 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010139 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141}
10142
10143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144// Return the property type calculated from the property details.
10145// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147 ASSERT(args.length() == 1);
10148 CONVERT_CHECKED(Smi, details, args[0]);
10149 PropertyType type = PropertyDetails(details).type();
10150 return Smi::FromInt(static_cast<int>(type));
10151}
10152
10153
10154// Return the property attribute calculated from the property details.
10155// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010156RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010157 ASSERT(args.length() == 1);
10158 CONVERT_CHECKED(Smi, details, args[0]);
10159 PropertyAttributes attributes = PropertyDetails(details).attributes();
10160 return Smi::FromInt(static_cast<int>(attributes));
10161}
10162
10163
10164// Return the property insertion index calculated from the property details.
10165// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010166RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 ASSERT(args.length() == 1);
10168 CONVERT_CHECKED(Smi, details, args[0]);
10169 int index = PropertyDetails(details).index();
10170 return Smi::FromInt(index);
10171}
10172
10173
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174// Return property value from named interceptor.
10175// args[0]: object
10176// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010177RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010178 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 ASSERT(args.length() == 2);
10180 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10181 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10182 CONVERT_ARG_CHECKED(String, name, 1);
10183
10184 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010185 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186}
10187
10188
10189// Return element value from indexed interceptor.
10190// args[0]: object
10191// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010192RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194 ASSERT(args.length() == 2);
10195 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10196 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10197 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10198
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010199 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200}
10201
10202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010203RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204 ASSERT(args.length() >= 1);
10205 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010206 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010207 if (isolate->debug()->break_id() == 0 ||
10208 break_id != isolate->debug()->break_id()) {
10209 return isolate->Throw(
10210 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 }
10212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010214}
10215
10216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 ASSERT(args.length() == 1);
10220
10221 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010222 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010223 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10224 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010225 if (!maybe_result->ToObject(&result)) return maybe_result;
10226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227
10228 // Count all frames which are relevant to debugging stack trace.
10229 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010231 if (id == StackFrame::NO_ID) {
10232 // If there is no JavaScript stack frame count is 0.
10233 return Smi::FromInt(0);
10234 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010235
10236 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10237 n += it.frame()->GetInlineCount();
10238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 return Smi::FromInt(n);
10240}
10241
10242
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010243class FrameInspector {
10244 public:
10245 FrameInspector(JavaScriptFrame* frame,
10246 int inlined_frame_index,
10247 Isolate* isolate)
10248 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10249 // Calculate the deoptimized frame.
10250 if (frame->is_optimized()) {
10251 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10252 frame, inlined_frame_index, isolate);
10253 }
10254 has_adapted_arguments_ = frame_->has_adapted_arguments();
10255 is_optimized_ = frame_->is_optimized();
10256 }
10257
10258 ~FrameInspector() {
10259 // Get rid of the calculated deoptimized frame if any.
10260 if (deoptimized_frame_ != NULL) {
10261 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10262 isolate_);
10263 }
10264 }
10265
10266 int GetParametersCount() {
10267 return is_optimized_
10268 ? deoptimized_frame_->parameters_count()
10269 : frame_->ComputeParametersCount();
10270 }
10271 int expression_count() { return deoptimized_frame_->expression_count(); }
10272 Object* GetFunction() {
10273 return is_optimized_
10274 ? deoptimized_frame_->GetFunction()
10275 : frame_->function();
10276 }
10277 Object* GetParameter(int index) {
10278 return is_optimized_
10279 ? deoptimized_frame_->GetParameter(index)
10280 : frame_->GetParameter(index);
10281 }
10282 Object* GetExpression(int index) {
10283 return is_optimized_
10284 ? deoptimized_frame_->GetExpression(index)
10285 : frame_->GetExpression(index);
10286 }
10287
10288 // To inspect all the provided arguments the frame might need to be
10289 // replaced with the arguments frame.
10290 void SetArgumentsFrame(JavaScriptFrame* frame) {
10291 ASSERT(has_adapted_arguments_);
10292 frame_ = frame;
10293 is_optimized_ = frame_->is_optimized();
10294 ASSERT(!is_optimized_);
10295 }
10296
10297 private:
10298 JavaScriptFrame* frame_;
10299 DeoptimizedFrameInfo* deoptimized_frame_;
10300 Isolate* isolate_;
10301 bool is_optimized_;
10302 bool has_adapted_arguments_;
10303
10304 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10305};
10306
10307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308static const int kFrameDetailsFrameIdIndex = 0;
10309static const int kFrameDetailsReceiverIndex = 1;
10310static const int kFrameDetailsFunctionIndex = 2;
10311static const int kFrameDetailsArgumentCountIndex = 3;
10312static const int kFrameDetailsLocalCountIndex = 4;
10313static const int kFrameDetailsSourcePositionIndex = 5;
10314static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010315static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010316static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010317static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318
10319// Return an array with frame details
10320// args[0]: number: break id
10321// args[1]: number: frame index
10322//
10323// The array returned contains the following information:
10324// 0: Frame id
10325// 1: Receiver
10326// 2: Function
10327// 3: Argument count
10328// 4: Local count
10329// 5: Source position
10330// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010331// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010332// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333// Arguments name, value
10334// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010335// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010336RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 ASSERT(args.length() == 2);
10339
10340 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010341 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010342 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10343 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010344 if (!maybe_check->ToObject(&check)) return maybe_check;
10345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348
10349 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010351 if (id == StackFrame::NO_ID) {
10352 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010353 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010354 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010355
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010356 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010359 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010361 if (index < count + it.frame()->GetInlineCount()) break;
10362 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010366 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010367 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010368 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010369 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010370 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372 // Traverse the saved contexts chain to find the active context for the
10373 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010375 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010376 save = save->prev();
10377 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010378 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010379
10380 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382
10383 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010385 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010387 // Check for constructor frame. Inlined frames cannot be construct calls.
10388 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010389 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010390 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010392 // Get scope info and read from it for local variable information.
10393 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010394 Handle<SharedFunctionInfo> shared(function->shared());
10395 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010396 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010397 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399 // Get the locals names and values into a temporary array.
10400 //
10401 // TODO(1240907): Hide compiler-introduced stack variables
10402 // (e.g. .result)? For users of the debugger, they will probably be
10403 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 Handle<FixedArray> locals =
10405 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010407 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010408 int i = 0;
10409 for (; i < info.number_of_stack_slots(); ++i) {
10410 // Use the value from the stack.
10411 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010412 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010413 }
10414 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010415 // Get the context containing declarations.
10416 Handle<Context> context(
10417 Context::cast(it.frame()->context())->declaration_context());
10418 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010419 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010420 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010422 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423 }
10424 }
10425
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010426 // Check whether this frame is positioned at return. If not top
10427 // frame or if the frame is optimized it cannot be at a return.
10428 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010429 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010430 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010431 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010432
10433 // If positioned just before return find the value to be returned and add it
10434 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010435 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010436 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010437 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010438 Address internal_frame_sp = NULL;
10439 while (!it2.done()) {
10440 if (it2.frame()->is_internal()) {
10441 internal_frame_sp = it2.frame()->sp();
10442 } else {
10443 if (it2.frame()->is_java_script()) {
10444 if (it2.frame()->id() == it.frame()->id()) {
10445 // The internal frame just before the JavaScript frame contains the
10446 // value to return on top. A debug break at return will create an
10447 // internal frame to store the return value (eax/rax/r0) before
10448 // entering the debug break exit frame.
10449 if (internal_frame_sp != NULL) {
10450 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 Handle<Object>(Memory::Object_at(internal_frame_sp),
10452 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010453 break;
10454 }
10455 }
10456 }
10457
10458 // Indicate that the previous frame was not an internal frame.
10459 internal_frame_sp = NULL;
10460 }
10461 it2.Advance();
10462 }
10463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464
10465 // Now advance to the arguments adapter frame (if any). It contains all
10466 // the provided parameters whereas the function frame always have the number
10467 // of arguments matching the functions parameters. The rest of the
10468 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010469 if (it.frame()->has_adapted_arguments()) {
10470 it.AdvanceToArgumentsFrame();
10471 frame_inspector.SetArgumentsFrame(it.frame());
10472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473
10474 // Find the number of arguments to fill. At least fill the number of
10475 // parameters for the function and fill more if more parameters are provided.
10476 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010477 if (argument_count < frame_inspector.GetParametersCount()) {
10478 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010480#ifdef DEBUG
10481 if (it.frame()->is_optimized()) {
10482 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10483 }
10484#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485
10486 // Calculate the size of the result.
10487 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010488 2 * (argument_count + info.NumberOfLocals()) +
10489 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491
10492 // Add the frame id.
10493 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10494
10495 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010496 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497
10498 // Add the arguments count.
10499 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10500
10501 // Add the locals count
10502 details->set(kFrameDetailsLocalCountIndex,
10503 Smi::FromInt(info.NumberOfLocals()));
10504
10505 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010506 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10508 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510 }
10511
10512 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010515 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010516 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010517
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010518 // Add flags to indicate information on whether this frame is
10519 // bit 0: invoked in the debugger context.
10520 // bit 1: optimized frame.
10521 // bit 2: inlined in optimized frame
10522 int flags = 0;
10523 if (*save->context() == *isolate->debug()->debug_context()) {
10524 flags |= 1 << 0;
10525 }
10526 if (it.frame()->is_optimized()) {
10527 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010528 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010529 }
10530 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531
10532 // Fill the dynamic part.
10533 int details_index = kFrameDetailsFirstDynamicIndex;
10534
10535 // Add arguments name and value.
10536 for (int i = 0; i < argument_count; i++) {
10537 // Name of the argument.
10538 if (i < info.number_of_parameters()) {
10539 details->set(details_index++, *info.parameter_name(i));
10540 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010541 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 }
10543
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010544 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010545 if (i < it.frame()->ComputeParametersCount()) {
10546 // Get the value from the stack.
10547 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010549 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550 }
10551 }
10552
10553 // Add locals name and value from the temporary copy from the function frame.
10554 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10555 details->set(details_index++, locals->get(i));
10556 }
10557
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010558 // Add the value being returned.
10559 if (at_return) {
10560 details->set(details_index++, *return_value);
10561 }
10562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 // Add the receiver (same as in function frame).
10564 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10565 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010567 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10568 // If the receiver is not a JSObject and the function is not a
10569 // builtin or strict-mode we have hit an optimization where a
10570 // value object is not converted into a wrapped JS objects. To
10571 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 // by creating correct wrapper object based on the calling frame's
10573 // global context.
10574 it.Advance();
10575 Handle<Context> calling_frames_global_context(
10576 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010577 receiver =
10578 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579 }
10580 details->set(kFrameDetailsReceiverIndex, *receiver);
10581
10582 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584}
10585
10586
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010587// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010588static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010589 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010590 Handle<SerializedScopeInfo> serialized_scope_info,
10591 ScopeInfo<>& scope_info,
10592 Handle<Context> context,
10593 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594 // Fill all context locals to the context extension.
10595 for (int i = Context::MIN_CONTEXT_SLOTS;
10596 i < scope_info.number_of_context_slots();
10597 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010598 int context_index = serialized_scope_info->ContextSlotIndex(
10599 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010600
whesse@chromium.org7b260152011-06-20 15:33:18 +000010601 RETURN_IF_EMPTY_HANDLE_VALUE(
10602 isolate,
10603 SetProperty(scope_object,
10604 scope_info.context_slot_name(i),
10605 Handle<Object>(context->get(context_index), isolate),
10606 NONE,
10607 kNonStrictMode),
10608 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010609 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010610
10611 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010612}
10613
10614
10615// Create a plain JSObject which materializes the local scope for the specified
10616// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010617static Handle<JSObject> MaterializeLocalScope(
10618 Isolate* isolate,
10619 JavaScriptFrame* frame,
10620 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010621 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010622 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010623 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10624 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010625 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010626
10627 // Allocate and initialize a JSObject with all the arguments, stack locals
10628 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010629 Handle<JSObject> local_scope =
10630 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010631
10632 // First fill all parameters.
10633 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010634 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010635 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010636 SetProperty(local_scope,
10637 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010638 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010639 NONE,
10640 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010641 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010642 }
10643
10644 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010645 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010646 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010648 SetProperty(local_scope,
10649 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010650 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010651 NONE,
10652 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010653 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010654 }
10655
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010656 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10657 // Third fill all context locals.
10658 Handle<Context> frame_context(Context::cast(frame->context()));
10659 Handle<Context> function_context(frame_context->declaration_context());
10660 if (!CopyContextLocalsToScopeObject(isolate,
10661 serialized_scope_info, scope_info,
10662 function_context, local_scope)) {
10663 return Handle<JSObject>();
10664 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010665
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010666 // Finally copy any properties from the function context extension.
10667 // These will be variables introduced by eval.
10668 if (function_context->closure() == *function) {
10669 if (function_context->has_extension() &&
10670 !function_context->IsGlobalContext()) {
10671 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10672 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10673 for (int i = 0; i < keys->length(); i++) {
10674 // Names of variables introduced by eval are strings.
10675 ASSERT(keys->get(i)->IsString());
10676 Handle<String> key(String::cast(keys->get(i)));
10677 RETURN_IF_EMPTY_HANDLE_VALUE(
10678 isolate,
10679 SetProperty(local_scope,
10680 key,
10681 GetProperty(ext, key),
10682 NONE,
10683 kNonStrictMode),
10684 Handle<JSObject>());
10685 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010686 }
10687 }
10688 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010689
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010690 return local_scope;
10691}
10692
10693
10694// Create a plain JSObject which materializes the closure content for the
10695// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10697 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010698 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010699
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010700 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010701 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10702 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010703
10704 // Allocate and initialize a JSObject with all the content of theis function
10705 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 Handle<JSObject> closure_scope =
10707 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010708
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010709 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 if (!CopyContextLocalsToScopeObject(isolate,
10711 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010712 context, closure_scope)) {
10713 return Handle<JSObject>();
10714 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010715
10716 // Finally copy any properties from the function context extension. This will
10717 // be variables introduced by eval.
10718 if (context->has_extension()) {
10719 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010720 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010721 for (int i = 0; i < keys->length(); i++) {
10722 // Names of variables introduced by eval are strings.
10723 ASSERT(keys->get(i)->IsString());
10724 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010725 RETURN_IF_EMPTY_HANDLE_VALUE(
10726 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010727 SetProperty(closure_scope,
10728 key,
10729 GetProperty(ext, key),
10730 NONE,
10731 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010732 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010733 }
10734 }
10735
10736 return closure_scope;
10737}
10738
10739
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010740// Create a plain JSObject which materializes the scope for the specified
10741// catch context.
10742static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10743 Handle<Context> context) {
10744 ASSERT(context->IsCatchContext());
10745 Handle<String> name(String::cast(context->extension()));
10746 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10747 Handle<JSObject> catch_scope =
10748 isolate->factory()->NewJSObject(isolate->object_function());
10749 RETURN_IF_EMPTY_HANDLE_VALUE(
10750 isolate,
10751 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10752 Handle<JSObject>());
10753 return catch_scope;
10754}
10755
10756
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010757// Create a plain JSObject which materializes the block scope for the specified
10758// block context.
10759static Handle<JSObject> MaterializeBlockScope(
10760 Isolate* isolate,
10761 Handle<Context> context) {
10762 ASSERT(context->IsBlockContext());
10763 Handle<SerializedScopeInfo> serialized_scope_info(
10764 SerializedScopeInfo::cast(context->extension()));
10765 ScopeInfo<> scope_info(*serialized_scope_info);
10766
10767 // Allocate and initialize a JSObject with all the arguments, stack locals
10768 // heap locals and extension properties of the debugged function.
10769 Handle<JSObject> block_scope =
10770 isolate->factory()->NewJSObject(isolate->object_function());
10771
10772 // Fill all context locals.
10773 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10774 if (!CopyContextLocalsToScopeObject(isolate,
10775 serialized_scope_info, scope_info,
10776 context, block_scope)) {
10777 return Handle<JSObject>();
10778 }
10779 }
10780
10781 return block_scope;
10782}
10783
10784
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785// Iterate over the actual scopes visible from a stack frame. All scopes are
10786// backed by an actual context except the local scope, which is inserted
10787// "artifically" in the context chain.
10788class ScopeIterator {
10789 public:
10790 enum ScopeType {
10791 ScopeTypeGlobal = 0,
10792 ScopeTypeLocal,
10793 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010794 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010795 ScopeTypeCatch,
10796 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797 };
10798
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010799 ScopeIterator(Isolate* isolate,
10800 JavaScriptFrame* frame,
10801 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010802 : isolate_(isolate),
10803 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010804 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010805 function_(JSFunction::cast(frame->function())),
10806 context_(Context::cast(frame->context())),
10807 local_done_(false),
10808 at_local_(false) {
10809
10810 // Check whether the first scope is actually a local scope.
10811 if (context_->IsGlobalContext()) {
10812 // If there is a stack slot for .result then this local scope has been
10813 // created for evaluating top level code and it is not a real local scope.
10814 // Checking for the existence of .result seems fragile, but the scope info
10815 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010816 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010818 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010819 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010820 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010821 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010822 // The context_ is a block or with or catch block from the outer function.
10823 ASSERT(context_->IsWithContext() ||
10824 context_->IsCatchContext() ||
10825 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010826 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010827 }
10828 }
10829
10830 // More scopes?
10831 bool Done() { return context_.is_null(); }
10832
10833 // Move to the next scope.
10834 void Next() {
10835 // If at a local scope mark the local scope as passed.
10836 if (at_local_) {
10837 at_local_ = false;
10838 local_done_ = true;
10839
10840 // If the current context is not associated with the local scope the
10841 // current context is the next real scope, so don't move to the next
10842 // context in this case.
10843 if (context_->closure() != *function_) {
10844 return;
10845 }
10846 }
10847
10848 // The global scope is always the last in the chain.
10849 if (context_->IsGlobalContext()) {
10850 context_ = Handle<Context>();
10851 return;
10852 }
10853
10854 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010855 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010856
10857 // If passing the local scope indicate that the current scope is now the
10858 // local scope.
10859 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010860 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010861 at_local_ = true;
10862 }
10863 }
10864
10865 // Return the type of the current scope.
10866 int Type() {
10867 if (at_local_) {
10868 return ScopeTypeLocal;
10869 }
10870 if (context_->IsGlobalContext()) {
10871 ASSERT(context_->global()->IsGlobalObject());
10872 return ScopeTypeGlobal;
10873 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010874 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010875 return ScopeTypeClosure;
10876 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010877 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010878 return ScopeTypeCatch;
10879 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010880 if (context_->IsBlockContext()) {
10881 return ScopeTypeBlock;
10882 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010883 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010884 return ScopeTypeWith;
10885 }
10886
10887 // Return the JavaScript object with the content of the current scope.
10888 Handle<JSObject> ScopeObject() {
10889 switch (Type()) {
10890 case ScopeIterator::ScopeTypeGlobal:
10891 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010892 case ScopeIterator::ScopeTypeLocal:
10893 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010894 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010895 case ScopeIterator::ScopeTypeWith:
10896 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010897 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10898 case ScopeIterator::ScopeTypeCatch:
10899 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010900 case ScopeIterator::ScopeTypeClosure:
10901 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010902 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010903 case ScopeIterator::ScopeTypeBlock:
10904 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010905 }
10906 UNREACHABLE();
10907 return Handle<JSObject>();
10908 }
10909
10910 // Return the context for this scope. For the local context there might not
10911 // be an actual context.
10912 Handle<Context> CurrentContext() {
10913 if (at_local_ && context_->closure() != *function_) {
10914 return Handle<Context>();
10915 }
10916 return context_;
10917 }
10918
10919#ifdef DEBUG
10920 // Debug print of the content of the current scope.
10921 void DebugPrint() {
10922 switch (Type()) {
10923 case ScopeIterator::ScopeTypeGlobal:
10924 PrintF("Global:\n");
10925 CurrentContext()->Print();
10926 break;
10927
10928 case ScopeIterator::ScopeTypeLocal: {
10929 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010930 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010931 scope_info.Print();
10932 if (!CurrentContext().is_null()) {
10933 CurrentContext()->Print();
10934 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010935 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010936 if (extension->IsJSContextExtensionObject()) {
10937 extension->Print();
10938 }
10939 }
10940 }
10941 break;
10942 }
10943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010944 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010945 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010946 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010947 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010948
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010949 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010950 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010951 CurrentContext()->extension()->Print();
10952 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010953 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010954
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010955 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010956 PrintF("Closure:\n");
10957 CurrentContext()->Print();
10958 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010959 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010960 if (extension->IsJSContextExtensionObject()) {
10961 extension->Print();
10962 }
10963 }
10964 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010965
10966 default:
10967 UNREACHABLE();
10968 }
10969 PrintF("\n");
10970 }
10971#endif
10972
10973 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010975 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010976 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010977 Handle<JSFunction> function_;
10978 Handle<Context> context_;
10979 bool local_done_;
10980 bool at_local_;
10981
10982 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10983};
10984
10985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010986RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010988 ASSERT(args.length() == 2);
10989
10990 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010991 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010992 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10993 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010994 if (!maybe_check->ToObject(&check)) return maybe_check;
10995 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010996 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10997
10998 // Get the frame where the debugging is performed.
10999 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011000 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011001 JavaScriptFrame* frame = it.frame();
11002
11003 // Count the visible scopes.
11004 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011005 for (ScopeIterator it(isolate, frame, 0);
11006 !it.Done();
11007 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008 n++;
11009 }
11010
11011 return Smi::FromInt(n);
11012}
11013
11014
11015static const int kScopeDetailsTypeIndex = 0;
11016static const int kScopeDetailsObjectIndex = 1;
11017static const int kScopeDetailsSize = 2;
11018
11019// Return an array with scope details
11020// args[0]: number: break id
11021// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011022// args[2]: number: inlined frame index
11023// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011024//
11025// The array returned contains the following information:
11026// 0: Scope type
11027// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011028RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011029 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011030 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011031
11032 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011033 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011034 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11035 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011036 if (!maybe_check->ToObject(&check)) return maybe_check;
11037 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011039 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11040 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011041
11042 // Get the frame where the debugging is performed.
11043 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011044 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045 JavaScriptFrame* frame = frame_it.frame();
11046
11047 // Find the requested scope.
11048 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011049 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 for (; !it.Done() && n < index; it.Next()) {
11051 n++;
11052 }
11053 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011055 }
11056
11057 // Calculate the size of the result.
11058 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011059 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011060
11061 // Fill in scope details.
11062 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011063 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011065 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011067 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011068}
11069
11070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011071RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 ASSERT(args.length() == 0);
11074
11075#ifdef DEBUG
11076 // Print the scopes for the top frame.
11077 StackFrameLocator locator;
11078 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011079 for (ScopeIterator it(isolate, frame, 0);
11080 !it.Done();
11081 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082 it.DebugPrint();
11083 }
11084#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011085 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011086}
11087
11088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011089RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011090 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011091 ASSERT(args.length() == 1);
11092
11093 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011094 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011095 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11096 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011097 if (!maybe_result->ToObject(&result)) return maybe_result;
11098 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011099
11100 // Count all archived V8 threads.
11101 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011102 for (ThreadState* thread =
11103 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011104 thread != NULL;
11105 thread = thread->Next()) {
11106 n++;
11107 }
11108
11109 // Total number of threads is current thread and archived threads.
11110 return Smi::FromInt(n + 1);
11111}
11112
11113
11114static const int kThreadDetailsCurrentThreadIndex = 0;
11115static const int kThreadDetailsThreadIdIndex = 1;
11116static const int kThreadDetailsSize = 2;
11117
11118// Return an array with thread details
11119// args[0]: number: break id
11120// args[1]: number: thread index
11121//
11122// The array returned contains the following information:
11123// 0: Is current thread?
11124// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011125RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011127 ASSERT(args.length() == 2);
11128
11129 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011130 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011131 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11132 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011133 if (!maybe_check->ToObject(&check)) return maybe_check;
11134 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011135 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11136
11137 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011138 Handle<FixedArray> details =
11139 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011140
11141 // Thread index 0 is current thread.
11142 if (index == 0) {
11143 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011144 details->set(kThreadDetailsCurrentThreadIndex,
11145 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011146 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011147 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011148 } else {
11149 // Find the thread with the requested index.
11150 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011151 ThreadState* thread =
11152 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011153 while (index != n && thread != NULL) {
11154 thread = thread->Next();
11155 n++;
11156 }
11157 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011158 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011159 }
11160
11161 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011162 details->set(kThreadDetailsCurrentThreadIndex,
11163 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011164 details->set(kThreadDetailsThreadIdIndex,
11165 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011166 }
11167
11168 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011169 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011170}
11171
11172
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011173// Sets the disable break state
11174// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011175RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011176 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011177 ASSERT(args.length() == 1);
11178 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011179 isolate->debug()->set_disable_break(disable_break);
11180 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011181}
11182
11183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011185 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011186 ASSERT(args.length() == 1);
11187
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011188 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11189 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011190 // Find the number of break points
11191 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011192 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011195 Handle<FixedArray>::cast(break_locations));
11196}
11197
11198
11199// Set a break point in a function
11200// args[0]: function
11201// args[1]: number: break source position (within the function source)
11202// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011203RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011205 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011206 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11207 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011208 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11209 RUNTIME_ASSERT(source_position >= 0);
11210 Handle<Object> break_point_object_arg = args.at<Object>(2);
11211
11212 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11214 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011216 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011217}
11218
11219
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011220Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11221 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011222 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 // Iterate the heap looking for SharedFunctionInfo generated from the
11224 // script. The inner most SharedFunctionInfo containing the source position
11225 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011226 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011227 // which is found is not compiled it is compiled and the heap is iterated
11228 // again as the compilation might create inner functions from the newly
11229 // compiled function and the actual requested break point might be in one of
11230 // these functions.
11231 bool done = false;
11232 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011233 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011234 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011235 while (!done) {
11236 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011237 for (HeapObject* obj = iterator.next();
11238 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 if (obj->IsSharedFunctionInfo()) {
11240 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11241 if (shared->script() == *script) {
11242 // If the SharedFunctionInfo found has the requested script data and
11243 // contains the source position it is a candidate.
11244 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011245 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011246 start_position = shared->start_position();
11247 }
11248 if (start_position <= position &&
11249 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011250 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 // candidate this is the new candidate.
11252 if (target.is_null()) {
11253 target_start_position = start_position;
11254 target = shared;
11255 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011256 if (target_start_position == start_position &&
11257 shared->end_position() == target->end_position()) {
11258 // If a top-level function contain only one function
11259 // declartion the source for the top-level and the function is
11260 // the same. In that case prefer the non top-level function.
11261 if (!shared->is_toplevel()) {
11262 target_start_position = start_position;
11263 target = shared;
11264 }
11265 } else if (target_start_position <= start_position &&
11266 shared->end_position() <= target->end_position()) {
11267 // This containment check includes equality as a function inside
11268 // a top-level function can share either start or end position
11269 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011270 target_start_position = start_position;
11271 target = shared;
11272 }
11273 }
11274 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011275 }
11276 }
11277 }
11278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011279 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011280 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011281 }
11282
11283 // If the candidate found is compiled we are done. NOTE: when lazy
11284 // compilation of inner functions is introduced some additional checking
11285 // needs to be done here to compile inner functions.
11286 done = target->is_compiled();
11287 if (!done) {
11288 // If the candidate is not compiled compile it to reveal any inner
11289 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011290 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011291 }
11292 }
11293
11294 return *target;
11295}
11296
11297
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011298// Changes the state of a break point in a script and returns source position
11299// where break point was set. NOTE: Regarding performance see the NOTE for
11300// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301// args[0]: script to set break point in
11302// args[1]: number: break source position (within the script source)
11303// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011304RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011305 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011306 ASSERT(args.length() == 3);
11307 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11308 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11309 RUNTIME_ASSERT(source_position >= 0);
11310 Handle<Object> break_point_object_arg = args.at<Object>(2);
11311
11312 // Get the script from the script wrapper.
11313 RUNTIME_ASSERT(wrapper->value()->IsScript());
11314 Handle<Script> script(Script::cast(wrapper->value()));
11315
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011316 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011317 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011318 if (!result->IsUndefined()) {
11319 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11320 // Find position within function. The script position might be before the
11321 // source position of the first function.
11322 int position;
11323 if (shared->start_position() > source_position) {
11324 position = 0;
11325 } else {
11326 position = source_position - shared->start_position();
11327 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011329 position += shared->start_position();
11330 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333}
11334
11335
11336// Clear a break point
11337// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011338RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011339 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011340 ASSERT(args.length() == 1);
11341 Handle<Object> break_point_object_arg = args.at<Object>(0);
11342
11343 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011344 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011347}
11348
11349
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011350// Change the state of break on exceptions.
11351// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11352// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011353RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011354 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011355 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011356 RUNTIME_ASSERT(args[0]->IsNumber());
11357 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011358
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011359 // If the number doesn't match an enum value, the ChangeBreakOnException
11360 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011361 ExceptionBreakType type =
11362 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011363 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364 isolate->debug()->ChangeBreakOnException(type, enable);
11365 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011366}
11367
11368
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011369// Returns the state of break on exceptions
11370// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011371RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011372 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011373 ASSERT(args.length() == 1);
11374 RUNTIME_ASSERT(args[0]->IsNumber());
11375
11376 ExceptionBreakType type =
11377 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011378 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011379 return Smi::FromInt(result);
11380}
11381
11382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383// Prepare for stepping
11384// args[0]: break id for checking execution state
11385// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011386// args[2]: number of times to perform the step, for step out it is the number
11387// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011388RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011390 ASSERT(args.length() == 3);
11391 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011392 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011393 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11394 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011395 if (!maybe_check->ToObject(&check)) return maybe_check;
11396 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011397 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011398 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011399 }
11400
11401 // Get the step action and check validity.
11402 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11403 if (step_action != StepIn &&
11404 step_action != StepNext &&
11405 step_action != StepOut &&
11406 step_action != StepInMin &&
11407 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011409 }
11410
11411 // Get the number of steps.
11412 int step_count = NumberToInt32(args[2]);
11413 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011414 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011415 }
11416
ager@chromium.orga1645e22009-09-09 19:27:10 +000011417 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11422 step_count);
11423 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424}
11425
11426
11427// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011428RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011430 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431 isolate->debug()->ClearStepping();
11432 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433}
11434
11435
11436// Creates a copy of the with context chain. The copy of the context chain is
11437// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011438static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011439 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011440 Handle<Context> current,
11441 Handle<Context> base) {
11442 // At the end of the chain. Return the base context to link to.
11443 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11444 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445 }
11446
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011447 // Recursively copy the with and catch contexts.
11448 HandleScope scope(isolate);
11449 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011450 Handle<Context> new_previous =
11451 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011452 Handle<Context> new_current;
11453 if (current->IsCatchContext()) {
11454 Handle<String> name(String::cast(current->extension()));
11455 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11456 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011457 isolate->factory()->NewCatchContext(function,
11458 new_previous,
11459 name,
11460 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011461 } else if (current->IsBlockContext()) {
11462 Handle<SerializedScopeInfo> scope_info(
11463 SerializedScopeInfo::cast(current->extension()));
11464 new_current =
11465 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011466 // Copy context slots.
11467 int num_context_slots = scope_info->NumberOfContextSlots();
11468 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11469 new_current->set(i, current->get(i));
11470 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011471 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011472 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011473 Handle<JSObject> extension(JSObject::cast(current->extension()));
11474 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011475 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011476 }
11477 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478}
11479
11480
11481// Helper function to find or create the arguments object for
11482// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483static Handle<Object> GetArgumentsObject(Isolate* isolate,
11484 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011485 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011486 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011487 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488 const ScopeInfo<>* sinfo,
11489 Handle<Context> function_context) {
11490 // Try to find the value of 'arguments' to pass as parameter. If it is not
11491 // found (that is the debugged function does not reference 'arguments' and
11492 // does not support eval) then create an 'arguments' object.
11493 int index;
11494 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011495 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011496 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011497 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011498 }
11499 }
11500
11501 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011502 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11503 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011504 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 }
11507 }
11508
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011509 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11510
11511 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011512 Handle<JSObject> arguments =
11513 isolate->factory()->NewArgumentsObject(function, length);
11514 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011515
11516 AssertNoAllocation no_gc;
11517 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011519 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011521 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522 return arguments;
11523}
11524
11525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526static const char kSourceStr[] =
11527 "(function(arguments,__source__){return eval(__source__);})";
11528
11529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011531// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532// extension part has all the parameters and locals of the function on the
11533// stack frame. A function which calls eval with the code to evaluate is then
11534// compiled in this context and called in this context. As this context
11535// replaces the context of the function on the stack frame a new (empty)
11536// function is created as well to be used as the closure for the context.
11537// This function and the context acts as replacements for the function on the
11538// stack frame presenting the same view of the values of parameters and
11539// local variables as if the piece of JavaScript was evaluated at the point
11540// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011543
11544 // Check the execution state and decode arguments frame and source to be
11545 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011546 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011547 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011548 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11549 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011550 if (!maybe_check_result->ToObject(&check_result)) {
11551 return maybe_check_result;
11552 }
11553 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011555 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11556 CONVERT_ARG_CHECKED(String, source, 3);
11557 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11558 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011559
11560 // Handle the processing of break.
11561 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011562
11563 // Get the frame where the debugging is performed.
11564 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011565 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011566 JavaScriptFrame* frame = it.frame();
11567 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011568 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011569 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011570
11571 // Traverse the saved contexts chain to find the active context for the
11572 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011574 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 save = save->prev();
11576 }
11577 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 SaveContext savex(isolate);
11579 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580
11581 // Create the (empty) function replacing the function on the stack frame for
11582 // the purpose of evaluating in the context created below. It is important
11583 // that this function does not describe any parameters and local variables
11584 // in the context. If it does then this will cause problems with the lookup
11585 // in Context::Lookup, where context slots for parameters and local variables
11586 // are looked at before the extension object.
11587 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11589 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011590 go_between->set_context(function->context());
11591#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011592 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11594 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11595#endif
11596
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011597 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011598 Handle<JSObject> local_scope = MaterializeLocalScope(
11599 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601
11602 // Allocate a new context for the debug evaluation and set the extension
11603 // object build.
11604 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11606 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011607 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011609 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011610 Handle<Context> function_context;
11611 // Get the function's context if it has one.
11612 if (scope_info->HasHeapAllocatedLocals()) {
11613 function_context = Handle<Context>(frame_context->declaration_context());
11614 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011615 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011617 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011618 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011619 context =
11620 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011621 }
11622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011623 // Wrap the evaluation statement in a new function compiled in the newly
11624 // created context. The function has one parameter which has to be called
11625 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011626 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 isolate->factory()->NewStringFromAscii(
11631 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011632
11633 // Currently, the eval code will be executed in non-strict mode,
11634 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011635 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011636 Compiler::CompileEval(function_source,
11637 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011638 context->IsGlobalContext(),
11639 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011640 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011641 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011642 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011643
11644 // Invoke the result of the compilation to get the evaluation function.
11645 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 Handle<Object> evaluation_function =
11648 Execution::Call(compiled_function, receiver, 0, NULL,
11649 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011650 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011651
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011652 Handle<Object> arguments = GetArgumentsObject(isolate,
11653 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011655 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656
11657 // Invoke the evaluation function and return the result.
11658 const int argc = 2;
11659 Object** argv[argc] = { arguments.location(),
11660 Handle<Object>::cast(source).location() };
11661 Handle<Object> result =
11662 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11663 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011664 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011665
11666 // Skip the global proxy as it has no properties and always delegates to the
11667 // real global object.
11668 if (result->IsJSGlobalProxy()) {
11669 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11670 }
11671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 return *result;
11673}
11674
11675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011678
11679 // Check the execution state and decode arguments frame and source to be
11680 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011681 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011682 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011683 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11684 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011685 if (!maybe_check_result->ToObject(&check_result)) {
11686 return maybe_check_result;
11687 }
11688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011689 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011690 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011691 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011692
11693 // Handle the processing of break.
11694 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011695
11696 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700 top = top->prev();
11701 }
11702 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011703 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011704 }
11705
11706 // Get the global context now set to the top context from before the
11707 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011710 bool is_global = true;
11711
11712 if (additional_context->IsJSObject()) {
11713 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11715 isolate->factory()->empty_string(),
11716 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011717 go_between->set_context(*context);
11718 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 isolate->factory()->NewFunctionContext(
11720 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011721 context->set_extension(JSObject::cast(*additional_context));
11722 is_global = false;
11723 }
11724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011726 // Currently, the eval code will be executed in non-strict mode,
11727 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011728 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011729 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011730 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011731 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011732 Handle<JSFunction>(
11733 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11734 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735
11736 // Invoke the result of the compilation to get the evaluation function.
11737 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011739 Handle<Object> result =
11740 Execution::Call(compiled_function, receiver, 0, NULL,
11741 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011742 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743 return *result;
11744}
11745
11746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011747RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011748 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011749 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011751 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011752 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753
11754 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011755 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011756 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11757 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11758 // because using
11759 // instances->set(i, *GetScriptWrapper(script))
11760 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11761 // already have deferenced the instances handle.
11762 Handle<JSValue> wrapper = GetScriptWrapper(script);
11763 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 }
11765
11766 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011767 Handle<JSObject> result =
11768 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011769 Handle<JSArray>::cast(result)->SetContent(*instances);
11770 return *result;
11771}
11772
11773
11774// Helper function used by Runtime_DebugReferencedBy below.
11775static int DebugReferencedBy(JSObject* target,
11776 Object* instance_filter, int max_references,
11777 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 JSFunction* arguments_function) {
11779 NoHandleAllocation ha;
11780 AssertNoAllocation no_alloc;
11781
11782 // Iterate the heap.
11783 int count = 0;
11784 JSObject* last = NULL;
11785 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011786 HeapObject* heap_obj = NULL;
11787 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011788 (max_references == 0 || count < max_references)) {
11789 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 if (heap_obj->IsJSObject()) {
11791 // Skip context extension objects and argument arrays as these are
11792 // checked in the context of functions using them.
11793 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011794 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011795 obj->map()->constructor() == arguments_function) {
11796 continue;
11797 }
11798
11799 // Check if the JS object has a reference to the object looked for.
11800 if (obj->ReferencesObject(target)) {
11801 // Check instance filter if supplied. This is normally used to avoid
11802 // references from mirror objects (see Runtime_IsInPrototypeChain).
11803 if (!instance_filter->IsUndefined()) {
11804 Object* V = obj;
11805 while (true) {
11806 Object* prototype = V->GetPrototype();
11807 if (prototype->IsNull()) {
11808 break;
11809 }
11810 if (instance_filter == prototype) {
11811 obj = NULL; // Don't add this object.
11812 break;
11813 }
11814 V = prototype;
11815 }
11816 }
11817
11818 if (obj != NULL) {
11819 // Valid reference found add to instance array if supplied an update
11820 // count.
11821 if (instances != NULL && count < instances_size) {
11822 instances->set(count, obj);
11823 }
11824 last = obj;
11825 count++;
11826 }
11827 }
11828 }
11829 }
11830
11831 // Check for circular reference only. This can happen when the object is only
11832 // referenced from mirrors and has a circular reference in which case the
11833 // object is not really alive and would have been garbage collected if not
11834 // referenced from the mirror.
11835 if (count == 1 && last == target) {
11836 count = 0;
11837 }
11838
11839 // Return the number of referencing objects found.
11840 return count;
11841}
11842
11843
11844// Scan the heap for objects with direct references to an object
11845// args[0]: the object to find references to
11846// args[1]: constructor function for instances to exclude (Mirror)
11847// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011848RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849 ASSERT(args.length() == 3);
11850
11851 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853
11854 // Check parameters.
11855 CONVERT_CHECKED(JSObject, target, args[0]);
11856 Object* instance_filter = args[1];
11857 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11858 instance_filter->IsJSObject());
11859 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11860 RUNTIME_ASSERT(max_references >= 0);
11861
11862 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865 JSFunction* arguments_function =
11866 JSFunction::cast(arguments_boilerplate->map()->constructor());
11867
11868 // Get the number of referencing objects.
11869 int count;
11870 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011871 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872
11873 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011874 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011876 if (!maybe_object->ToObject(&object)) return maybe_object;
11877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 FixedArray* instances = FixedArray::cast(object);
11879
11880 // Fill the referencing objects.
11881 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011882 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883
11884 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011885 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11887 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011888 if (!maybe_result->ToObject(&result)) return maybe_result;
11889 }
11890 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 return result;
11892}
11893
11894
11895// Helper function used by Runtime_DebugConstructedBy below.
11896static int DebugConstructedBy(JSFunction* constructor, int max_references,
11897 FixedArray* instances, int instances_size) {
11898 AssertNoAllocation no_alloc;
11899
11900 // Iterate the heap.
11901 int count = 0;
11902 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011903 HeapObject* heap_obj = NULL;
11904 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905 (max_references == 0 || count < max_references)) {
11906 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 if (heap_obj->IsJSObject()) {
11908 JSObject* obj = JSObject::cast(heap_obj);
11909 if (obj->map()->constructor() == constructor) {
11910 // Valid reference found add to instance array if supplied an update
11911 // count.
11912 if (instances != NULL && count < instances_size) {
11913 instances->set(count, obj);
11914 }
11915 count++;
11916 }
11917 }
11918 }
11919
11920 // Return the number of referencing objects found.
11921 return count;
11922}
11923
11924
11925// Scan the heap for objects constructed by a specific function.
11926// args[0]: the constructor to find instances of
11927// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011928RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929 ASSERT(args.length() == 2);
11930
11931 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933
11934 // Check parameters.
11935 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11936 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11937 RUNTIME_ASSERT(max_references >= 0);
11938
11939 // Get the number of referencing objects.
11940 int count;
11941 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11942
11943 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011944 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011945 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011946 if (!maybe_object->ToObject(&object)) return maybe_object;
11947 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 FixedArray* instances = FixedArray::cast(object);
11949
11950 // Fill the referencing objects.
11951 count = DebugConstructedBy(constructor, max_references, instances, count);
11952
11953 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011954 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011955 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11956 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011957 if (!maybe_result->ToObject(&result)) return maybe_result;
11958 }
11959 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960 return result;
11961}
11962
11963
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011964// Find the effective prototype object as returned by __proto__.
11965// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011966RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011967 ASSERT(args.length() == 1);
11968
11969 CONVERT_CHECKED(JSObject, obj, args[0]);
11970
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011971 // Use the __proto__ accessor.
11972 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011973}
11974
11975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011976RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011977 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980}
11981
11982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011983RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011984#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011986 ASSERT(args.length() == 1);
11987 // Get the function and make sure it is compiled.
11988 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011989 Handle<SharedFunctionInfo> shared(func->shared());
11990 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011991 return Failure::Exception();
11992 }
11993 func->code()->PrintLn();
11994#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011996}
ager@chromium.org9085a012009-05-11 19:22:57 +000011997
11998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011999RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012000#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012001 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012002 ASSERT(args.length() == 1);
12003 // Get the function and make sure it is compiled.
12004 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012005 Handle<SharedFunctionInfo> shared(func->shared());
12006 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012007 return Failure::Exception();
12008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012009 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012010#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012011 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012012}
12013
12014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012016 NoHandleAllocation ha;
12017 ASSERT(args.length() == 1);
12018
12019 CONVERT_CHECKED(JSFunction, f, args[0]);
12020 return f->shared()->inferred_name();
12021}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012022
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012023
12024static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012025 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012026 AssertNoAllocation no_allocations;
12027
12028 int counter = 0;
12029 int buffer_size = buffer->length();
12030 HeapIterator iterator;
12031 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12032 ASSERT(obj != NULL);
12033 if (!obj->IsSharedFunctionInfo()) {
12034 continue;
12035 }
12036 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12037 if (shared->script() != script) {
12038 continue;
12039 }
12040 if (counter < buffer_size) {
12041 buffer->set(counter, shared);
12042 }
12043 counter++;
12044 }
12045 return counter;
12046}
12047
12048// For a script finds all SharedFunctionInfo's in the heap that points
12049// to this script. Returns JSArray of SharedFunctionInfo wrapped
12050// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012051RUNTIME_FUNCTION(MaybeObject*,
12052 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012053 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012054 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012055 CONVERT_CHECKED(JSValue, script_value, args[0]);
12056
12057 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12058
12059 const int kBufferSize = 32;
12060
12061 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012063 int number = FindSharedFunctionInfosForScript(*script, *array);
12064 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012065 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012066 FindSharedFunctionInfosForScript(*script, *array);
12067 }
12068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012069 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012070 result->set_length(Smi::FromInt(number));
12071
12072 LiveEdit::WrapSharedFunctionInfos(result);
12073
12074 return *result;
12075}
12076
12077// For a script calculates compilation information about all its functions.
12078// The script source is explicitly specified by the second argument.
12079// The source of the actual script is not used, however it is important that
12080// all generated code keeps references to this particular instance of script.
12081// Returns a JSArray of compilation infos. The array is ordered so that
12082// each function with all its descendant is always stored in a continues range
12083// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012084RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012085 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012087 CONVERT_CHECKED(JSValue, script, args[0]);
12088 CONVERT_ARG_CHECKED(String, source, 1);
12089 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12090
12091 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012094 return Failure::Exception();
12095 }
12096
12097 return result;
12098}
12099
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012100// Changes the source of the script to a new_source.
12101// If old_script_name is provided (i.e. is a String), also creates a copy of
12102// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012103RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012104 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012105 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012106 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12107 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012109
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012110 CONVERT_CHECKED(Script, original_script_pointer,
12111 original_script_value->value());
12112 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012113
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012114 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12115 new_source,
12116 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012117
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012118 if (old_script->IsScript()) {
12119 Handle<Script> script_handle(Script::cast(old_script));
12120 return *(GetScriptWrapper(script_handle));
12121 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012122 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012123 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012124}
12125
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012127RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012128 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012130 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12131 return LiveEdit::FunctionSourceUpdated(shared_info);
12132}
12133
12134
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012135// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012136RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012137 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012138 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012139 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12140 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12141
ager@chromium.orgac091b72010-05-05 07:34:42 +000012142 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012143}
12144
12145// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012146RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012147 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 HandleScope scope(isolate);
12149 Handle<Object> function_object(args[0], isolate);
12150 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012151
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012152 if (function_object->IsJSValue()) {
12153 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12154 if (script_object->IsJSValue()) {
12155 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012157 }
12158
12159 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12160 } else {
12161 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12162 // and we check it in this function.
12163 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012166}
12167
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012168
12169// In a code of a parent function replaces original function as embedded object
12170// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012171RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012172 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012174
12175 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12176 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12177 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12178
12179 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12180 subst_wrapper);
12181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012183}
12184
12185
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012186// Updates positions of a shared function info (first parameter) according
12187// to script source change. Text change is described in second parameter as
12188// array of groups of 3 numbers:
12189// (change_begin, change_end, change_end_new_position).
12190// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012191RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012192 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012194 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12195 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12196
ager@chromium.orgac091b72010-05-05 07:34:42 +000012197 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012198}
12199
12200
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012201// For array of SharedFunctionInfo's (each wrapped in JSValue)
12202// checks that none of them have activations on stacks (of any thread).
12203// Returns array of the same length with corresponding results of
12204// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012205RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012206 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012207 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012208 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012209 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012210
ager@chromium.org357bf652010-04-12 11:30:10 +000012211 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012212}
12213
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012214// Compares 2 strings line-by-line, then token-wise and returns diff in form
12215// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12216// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012217RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012218 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012220 CONVERT_ARG_CHECKED(String, s1, 0);
12221 CONVERT_ARG_CHECKED(String, s2, 1);
12222
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012223 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012224}
12225
12226
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012227// A testing entry. Returns statement position which is the closest to
12228// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012229RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012230 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012231 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012232 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12233 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012236
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012237 if (code->kind() != Code::FUNCTION &&
12238 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012239 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012240 }
12241
12242 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012243 int closest_pc = 0;
12244 int distance = kMaxInt;
12245 while (!it.done()) {
12246 int statement_position = static_cast<int>(it.rinfo()->data());
12247 // Check if this break point is closer that what was previously found.
12248 if (source_position <= statement_position &&
12249 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012250 closest_pc =
12251 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012252 distance = statement_position - source_position;
12253 // Check whether we can't get any closer.
12254 if (distance == 0) break;
12255 }
12256 it.next();
12257 }
12258
12259 return Smi::FromInt(closest_pc);
12260}
12261
12262
ager@chromium.org357bf652010-04-12 11:30:10 +000012263// Calls specified function with or without entering the debugger.
12264// This is used in unit tests to run code as if debugger is entered or simply
12265// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012266RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012267 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012269 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12270 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12271
12272 Handle<Object> result;
12273 bool pending_exception;
12274 {
12275 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012276 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012277 &pending_exception);
12278 } else {
12279 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012280 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012281 &pending_exception);
12282 }
12283 }
12284 if (!pending_exception) {
12285 return *result;
12286 } else {
12287 return Failure::Exception();
12288 }
12289}
12290
12291
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012292// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012293RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012294 CONVERT_CHECKED(String, arg, args[0]);
12295 SmartPointer<char> flags =
12296 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12297 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012298 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012299}
12300
12301
12302// Performs a GC.
12303// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012304RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012305 isolate->heap()->CollectAllGarbage(true);
12306 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012307}
12308
12309
12310// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012311RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012312 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012313 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012314 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012315 }
12316 return Smi::FromInt(usage);
12317}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012318
12319
12320// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012321RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012322#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012323 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012324#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012325 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012326#endif
12327}
12328
12329
12330// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012331RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012332#ifdef LIVE_OBJECT_LIST
12333 return LiveObjectList::Capture();
12334#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012335 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012336#endif
12337}
12338
12339
12340// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012341RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012342#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012343 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012344 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012345 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012346#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012347 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012348#endif
12349}
12350
12351
12352// Generates the response to a debugger request for a dump of the objects
12353// contained in the difference between the captured live object lists
12354// specified by id1 and id2.
12355// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12356// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012357RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012358#ifdef LIVE_OBJECT_LIST
12359 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012360 CONVERT_SMI_ARG_CHECKED(id1, 0);
12361 CONVERT_SMI_ARG_CHECKED(id2, 1);
12362 CONVERT_SMI_ARG_CHECKED(start, 2);
12363 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012364 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12365 EnterDebugger enter_debugger;
12366 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12367#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012369#endif
12370}
12371
12372
12373// Gets the specified object as requested by the debugger.
12374// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012375RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012376#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012377 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012378 Object* result = LiveObjectList::GetObj(obj_id);
12379 return result;
12380#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012381 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012382#endif
12383}
12384
12385
12386// Gets the obj id for the specified address if valid.
12387// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012388RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012389#ifdef LIVE_OBJECT_LIST
12390 HandleScope scope;
12391 CONVERT_ARG_CHECKED(String, address, 0);
12392 Object* result = LiveObjectList::GetObjId(address);
12393 return result;
12394#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012395 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012396#endif
12397}
12398
12399
12400// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012401RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012402#ifdef LIVE_OBJECT_LIST
12403 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012404 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012405 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12406 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12407 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12408 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12409 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12410
12411 Handle<JSObject> instance_filter;
12412 if (args[1]->IsJSObject()) {
12413 instance_filter = args.at<JSObject>(1);
12414 }
12415 bool verbose = false;
12416 if (args[2]->IsBoolean()) {
12417 verbose = args[2]->IsTrue();
12418 }
12419 int start = 0;
12420 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012421 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012422 }
12423 int limit = Smi::kMaxValue;
12424 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012425 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012426 }
12427
12428 return LiveObjectList::GetObjRetainers(obj_id,
12429 instance_filter,
12430 verbose,
12431 start,
12432 limit,
12433 filter_obj);
12434#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012435 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012436#endif
12437}
12438
12439
12440// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012441RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012442#ifdef LIVE_OBJECT_LIST
12443 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012444 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12445 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012446 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12447
12448 Handle<JSObject> instance_filter;
12449 if (args[2]->IsJSObject()) {
12450 instance_filter = args.at<JSObject>(2);
12451 }
12452
12453 Object* result =
12454 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12455 return result;
12456#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012458#endif
12459}
12460
12461
12462// Generates the response to a debugger request for a list of all
12463// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012464RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012465#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012466 CONVERT_SMI_ARG_CHECKED(start, 0);
12467 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012468 return LiveObjectList::Info(start, count);
12469#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012471#endif
12472}
12473
12474
12475// Gets a dump of the specified object as requested by the debugger.
12476// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012478#ifdef LIVE_OBJECT_LIST
12479 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012480 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012481 Object* result = LiveObjectList::PrintObj(obj_id);
12482 return result;
12483#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012484 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012485#endif
12486}
12487
12488
12489// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012490RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012491#ifdef LIVE_OBJECT_LIST
12492 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012493 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012494#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012496#endif
12497}
12498
12499
12500// Generates the response to a debugger request for a summary of the types
12501// of objects in the difference between the captured live object lists
12502// specified by id1 and id2.
12503// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12504// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012505RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012506#ifdef LIVE_OBJECT_LIST
12507 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012508 CONVERT_SMI_ARG_CHECKED(id1, 0);
12509 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012510 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12511
12512 EnterDebugger enter_debugger;
12513 return LiveObjectList::Summarize(id1, id2, filter_obj);
12514#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012515 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012516#endif
12517}
12518
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012519#endif // ENABLE_DEBUGGER_SUPPORT
12520
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012522RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012523 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012524 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012526}
12527
12528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012529RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012530 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012531 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012532 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012533}
12534
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536// Finds the script object from the script data. NOTE: This operation uses
12537// heap traversal to find the function generated for the source position
12538// for the requested break point. For lazily compiled functions several heap
12539// traversals might be required rendering this operation as a rather slow
12540// operation. However for setting break points which is normally done through
12541// some kind of user interaction the performance is not crucial.
12542static Handle<Object> Runtime_GetScriptFromScriptName(
12543 Handle<String> script_name) {
12544 // Scan the heap for Script objects to find the script with the requested
12545 // script data.
12546 Handle<Script> script;
12547 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012548 HeapObject* obj = NULL;
12549 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012550 // If a script is found check if it has the script data requested.
12551 if (obj->IsScript()) {
12552 if (Script::cast(obj)->name()->IsString()) {
12553 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12554 script = Handle<Script>(Script::cast(obj));
12555 }
12556 }
12557 }
12558 }
12559
12560 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012562
12563 // Return the script found.
12564 return GetScriptWrapper(script);
12565}
12566
12567
12568// Get the script object from script data. NOTE: Regarding performance
12569// see the NOTE for GetScriptFromScriptData.
12570// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012571RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012572 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573
12574 ASSERT(args.length() == 1);
12575
12576 CONVERT_CHECKED(String, script_name, args[0]);
12577
12578 // Find the requested script.
12579 Handle<Object> result =
12580 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12581 return *result;
12582}
12583
12584
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012585// Determines whether the given stack frame should be displayed in
12586// a stack trace. The caller is the error constructor that asked
12587// for the stack trace to be collected. The first time a construct
12588// call to this function is encountered it is skipped. The seen_caller
12589// in/out parameter is used to remember if the caller has been seen
12590// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012591static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12592 Object* caller,
12593 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012594 // Only display JS frames.
12595 if (!raw_frame->is_java_script())
12596 return false;
12597 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12598 Object* raw_fun = frame->function();
12599 // Not sure when this can happen but skip it just in case.
12600 if (!raw_fun->IsJSFunction())
12601 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012602 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012603 *seen_caller = true;
12604 return false;
12605 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012606 // Skip all frames until we've seen the caller.
12607 if (!(*seen_caller)) return false;
12608 // Also, skip the most obvious builtin calls. We recognize builtins
12609 // as (1) functions called with the builtins object as the receiver and
12610 // as (2) functions from native scripts called with undefined as the
12611 // receiver (direct calls to helper functions in the builtins
12612 // code). Some builtin calls (such as Number.ADD which is invoked
12613 // using 'call') are very difficult to recognize so we're leaving
12614 // them in for now.
12615 if (frame->receiver()->IsJSBuiltinsObject()) {
12616 return false;
12617 }
12618 JSFunction* fun = JSFunction::cast(raw_fun);
12619 Object* raw_script = fun->shared()->script();
12620 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12621 int script_type = Script::cast(raw_script)->type()->value();
12622 return script_type != Script::TYPE_NATIVE;
12623 }
12624 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012625}
12626
12627
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012628// Collect the raw data for a stack trace. Returns an array of 4
12629// element segments each containing a receiver, function, code and
12630// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012631RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012632 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012633 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012634 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 HandleScope scope(isolate);
12637 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012638
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012639 limit = Max(limit, 0); // Ensure that limit is not negative.
12640 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012641 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012642 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012643
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012644 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012645 // If the caller parameter is a function we skip frames until we're
12646 // under it before starting to collect.
12647 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012648 int cursor = 0;
12649 int frames_seen = 0;
12650 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012651 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012652 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012653 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012654 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012655 // Set initial size to the maximum inlining level + 1 for the outermost
12656 // function.
12657 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012658 frame->Summarize(&frames);
12659 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012660 if (cursor + 4 > elements->length()) {
12661 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12662 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012663 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012664 for (int i = 0; i < cursor; i++) {
12665 new_elements->set(i, elements->get(i));
12666 }
12667 elements = new_elements;
12668 }
12669 ASSERT(cursor + 4 <= elements->length());
12670
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012671 Handle<Object> recv = frames[i].receiver();
12672 Handle<JSFunction> fun = frames[i].function();
12673 Handle<Code> code = frames[i].code();
12674 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012675 elements->set(cursor++, *recv);
12676 elements->set(cursor++, *fun);
12677 elements->set(cursor++, *code);
12678 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012679 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012680 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012681 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012682 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012684 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012685 return *result;
12686}
12687
12688
ager@chromium.org3811b432009-10-28 14:53:37 +000012689// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012691 ASSERT_EQ(args.length(), 0);
12692
12693 NoHandleAllocation ha;
12694
12695 const char* version_string = v8::V8::GetVersion();
12696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012697 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12698 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012699}
12700
12701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012702RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012703 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012704 OS::PrintError("abort: %s\n",
12705 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012706 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012707 OS::Abort();
12708 UNREACHABLE();
12709 return NULL;
12710}
12711
12712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012713RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012714 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012715 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012716 Object* key = args[1];
12717
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012718 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012719 Object* o = cache->get(finger_index);
12720 if (o == key) {
12721 // The fastest case: hit the same place again.
12722 return cache->get(finger_index + 1);
12723 }
12724
12725 for (int i = finger_index - 2;
12726 i >= JSFunctionResultCache::kEntriesIndex;
12727 i -= 2) {
12728 o = cache->get(i);
12729 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012730 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012731 return cache->get(i + 1);
12732 }
12733 }
12734
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012735 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012736 ASSERT(size <= cache->length());
12737
12738 for (int i = size - 2; i > finger_index; i -= 2) {
12739 o = cache->get(i);
12740 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012741 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012742 return cache->get(i + 1);
12743 }
12744 }
12745
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012746 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012748
12749 Handle<JSFunctionResultCache> cache_handle(cache);
12750 Handle<Object> key_handle(key);
12751 Handle<Object> value;
12752 {
12753 Handle<JSFunction> factory(JSFunction::cast(
12754 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12755 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012757 // This handle is nor shared, nor used later, so it's safe.
12758 Object** argv[] = { key_handle.location() };
12759 bool pending_exception = false;
12760 value = Execution::Call(factory,
12761 receiver,
12762 1,
12763 argv,
12764 &pending_exception);
12765 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012766 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012767
12768#ifdef DEBUG
12769 cache_handle->JSFunctionResultCacheVerify();
12770#endif
12771
12772 // Function invocation may have cleared the cache. Reread all the data.
12773 finger_index = cache_handle->finger_index();
12774 size = cache_handle->size();
12775
12776 // If we have spare room, put new data into it, otherwise evict post finger
12777 // entry which is likely to be the least recently used.
12778 int index = -1;
12779 if (size < cache_handle->length()) {
12780 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12781 index = size;
12782 } else {
12783 index = finger_index + JSFunctionResultCache::kEntrySize;
12784 if (index == cache_handle->length()) {
12785 index = JSFunctionResultCache::kEntriesIndex;
12786 }
12787 }
12788
12789 ASSERT(index % 2 == 0);
12790 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12791 ASSERT(index < cache_handle->length());
12792
12793 cache_handle->set(index, *key_handle);
12794 cache_handle->set(index + 1, *value);
12795 cache_handle->set_finger_index(index);
12796
12797#ifdef DEBUG
12798 cache_handle->JSFunctionResultCacheVerify();
12799#endif
12800
12801 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012802}
12803
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012805RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012807 CONVERT_ARG_CHECKED(String, type, 0);
12808 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012809 return *isolate->factory()->NewJSMessageObject(
12810 type,
12811 arguments,
12812 0,
12813 0,
12814 isolate->factory()->undefined_value(),
12815 isolate->factory()->undefined_value(),
12816 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012817}
12818
12819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012821 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12822 return message->type();
12823}
12824
12825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012826RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012827 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12828 return message->arguments();
12829}
12830
12831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012832RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012833 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12834 return Smi::FromInt(message->start_position());
12835}
12836
12837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012838RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012839 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12840 return message->script();
12841}
12842
12843
kasper.lund44510672008-07-25 07:37:58 +000012844#ifdef DEBUG
12845// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12846// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012848 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012849 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012850#define COUNT_ENTRY(Name, argc, ressize) + 1
12851 int entry_count = 0
12852 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12853 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12854 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12855#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012856 Factory* factory = isolate->factory();
12857 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012858 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012859 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012860#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012861 { \
12862 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012863 Handle<String> name; \
12864 /* Inline runtime functions have an underscore in front of the name. */ \
12865 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012867 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12868 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012870 Vector<const char>(#Name, StrLength(#Name))); \
12871 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012872 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012873 pair_elements->set(0, *name); \
12874 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012875 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012876 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012877 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012878 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012880 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012881 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012882 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012883#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012884 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012886 return *result;
12887}
kasper.lund44510672008-07-25 07:37:58 +000012888#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012889
12890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012891RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012892 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012893 CONVERT_CHECKED(String, format, args[0]);
12894 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000012895 String::FlatContent format_content = format->GetFlatContent();
12896 RUNTIME_ASSERT(format_content.IsAscii());
12897 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898 LOGGER->LogRuntime(chars, elms);
12899 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012900}
12901
12902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012903RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012904 UNREACHABLE(); // implemented as macro in the parser
12905 return NULL;
12906}
12907
12908
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012909#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12910 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12911 CONVERT_CHECKED(JSObject, obj, args[0]); \
12912 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12913 }
12914
12915ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12916ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12917ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12918ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12919ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12920ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12921ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12922ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12923ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12924ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12925ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12926ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12927ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12928
12929#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012931// ----------------------------------------------------------------------------
12932// Implementation of Runtime
12933
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012934#define F(name, number_of_args, result_size) \
12935 { Runtime::k##name, Runtime::RUNTIME, #name, \
12936 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012937
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012938
12939#define I(name, number_of_args, result_size) \
12940 { Runtime::kInline##name, Runtime::INLINE, \
12941 "_" #name, NULL, number_of_args, result_size },
12942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012943static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012944 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012945 INLINE_FUNCTION_LIST(I)
12946 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012947};
12948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012950MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12951 Object* dictionary) {
12952 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012953 ASSERT(dictionary != NULL);
12954 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12955 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012956 Object* name_symbol;
12957 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012958 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012959 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12960 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012961 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012962 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12963 String::cast(name_symbol),
12964 Smi::FromInt(i),
12965 PropertyDetails(NONE, NORMAL));
12966 if (!maybe_dictionary->ToObject(&dictionary)) {
12967 // Non-recoverable failure. Calling code must restart heap
12968 // initialization.
12969 return maybe_dictionary;
12970 }
12971 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012972 }
12973 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012974}
12975
12976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012977const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12978 Heap* heap = name->GetHeap();
12979 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012980 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012981 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012982 int function_index = Smi::cast(smi_index)->value();
12983 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012984 }
12985 return NULL;
12986}
12987
12988
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012989const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012990 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12991}
12992
12993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012994void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012995 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012996 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012997 if (failure->IsRetryAfterGC()) {
12998 // Try to do a garbage collection; ignore it if it fails. The C
12999 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013000 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013001 } else {
13002 // Handle last resort GC and make sure to allow future allocations
13003 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013004 isolate->counters()->gc_last_resort_from_js()->Increment();
13005 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013006 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013007}
13008
13009
13010} } // namespace v8::internal